diff --git a/.gitignore b/.gitignore index 15205f4..593a970 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,13 @@ *.swp *.pyc +*~ jsdocs/ docs/ public/cocos2d.js public/tests.js +cocos2d-*.exe +cocos2d-*.gz +cocos2d-*.zip +.DS_Store +nbproject +tests/build/ diff --git a/.gitmodules b/.gitmodules index e910533..26c6397 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ -[submodule "tests/commonjs"] - path = tests/commonjs +[submodule "tests/src/commonjs"] + path = tests/src/commonjs url = https://github.com/commonjs/commonjs.git +[submodule "support/node-builds"] + path = support/node-builds + url = https://github.com/ajaxorg/node-builds.git diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..363579a --- /dev/null +++ b/.npmignore @@ -0,0 +1,12 @@ +support/ +.* +*.swp +*.pyc +*~ +jsdocs/ +docs/ +public/cocos2d.js +public/tests.js +cocos2d-*.exe +cocos2d-*.gz +cocos2d-*.zip diff --git a/LICENSE b/LICENSE index 6cd58c9..ef9e8f2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,27 +1,20 @@ -cocos2d-javascript is is released under the "Simplified BSD License": - -Copyright 2010 Ryan Williams. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY RYAN WILLIAMS ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the -authors and should not be interpreted as representing official policies, either expressed -or implied, of Ryan Williams. +Copyright (c) 2010-2011 Ryan Williams + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 054b294..0da9280 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,147 @@ -Check the LICENSE file licensing details. - -This is in the early stages of development and could break backwards compatibility at any time. - -* You can find me on Twitter: @cocos2djs -* Email: -* Website: -* Documentation: -* Forum: - -Creating a new project ----------------------- - -To create a new project you first need to get a copy of cocos2d-javascript. Grab the latest using git - - git clone git://github.com/ryanwilliams/cocos2d-javascript.git - -To create your initial project simply navigate to the cocos2d-javascript directory and run - - ./cocos new ~/Projects/MyApp - -This will create a new directory at that path with everything you need to -get started. It will also add cocos2d-javascript as a git submodule. If you -prefer to just copy the cocos2d-javascript code instead of using a git -submodule then use - - ./cocos new ~/Projects/MyApp -g - -Getting things running ----------------------- - -To get your project running simply navigate to the newly created directory run -the development web server - - ./cocos server - -And visit . There you will see a simple application -outputting your application name. - -Developing ----------- - -Everything you write will be in separate JavaScript files. These will be -compiled into a single file which also includes all your other resources -including images, sound files, map files, etc. - -The entry point for the code is path defined as "main.js" inside the in "make.js" file. - -In the public/index.html you will see <script src="https://github.com/appname.js"> tag to include the code. - -The web server will compile your code each time it is requested. This makes -development a lot easier. - -Run ./cocos server -h for help. - -Compiling your application --------------------------- - -To compile your code you run ./cocos make. Which reads the make.js file -to work out what you want to build. - -When built the resulting .js file will contain all your code aswell as all your -images and map files. This means you only need to update a single file and only -a single HTTP request is needed to serve everything. - -Run ./cocos make -h for help. - -Browser Support ---------------- - -I intend for this to work in Firefox, Chrome, Safari, Opera and IE9. I -mostly develop using Chrome so that's likely to have the best compatibility -until I get close to a proper release. - -Documentation -------------- - -Download JsDoc 2.3 (or 2.4) from . - -Copy that to /usr/local/jsdoc-toolkit or wherever you like and then run: - - JSDOC_HOME=/usr/local/jsdoc-toolkit ./jsdoc - -The documentation will appear in the 'docs' directory. - -© 2010 Ryan Williams - +Overview +======== + +Cocos2D JavaScript is an HTML5 port of the popular iPhone 2D graphics engine Cocos2D. It allows rapid development of 2D games and graphical applications which can run in any modern Web browser. + +Installation +============ + +Follow the instructions for your given platform or skip ahead to 'manual +installation' if you want to install from git. + +Windows +------- + +Download and launch the installer. + + + +Linux or Mac OS X using npm +--------------------------- + +If you have [Node.js][nodejs] and [npm][npm] installed you can install Cocos2D +JavaScript as a package. + + npm install cocos2d + +Linux or Mac OS X using ZIP archive +----------------------------------- + +If you don't have, or don't want to use npm, you can install by downloading the +latest ZIP. + + + +Then from your terminal run `sudo ./install.sh`. The script will copy Cocos2D +JavaScript to a global location of your choice and symlink the executable to +/usr/local/bin/cocos + +Manual Installation (all platforms) +----------------------------------- + +You don't need to use the installer if you don't want to. You can download the +latest ZIP or checkout the latest version from github. + +If you checkout from github and don't have Node.js installed, be sure to also +get the submodules as they include precompiled Node.js binaries. + + git submodule update --init + +With all the code read you can copy it to any place you want and from there use +the 'cocos.sh', 'cocos.bat' or .EXEs in _bin/_ as you would normally. + +Creating your first project +=========================== + +On Windows use the 'Create project' shortcut from your start menu to create and +select a location for your new project. + +On Linux and Mac OS X open your terminal and run: + + cocos new ~/my_first_project + +This will create a barebones project which simply draws the project name in the +centre of the screen. + +To test that it's working, on Windows double click the 'Serve project' shortcut +in your project's folder. + +On Linux and Mac OS X from your terminal run: + + cd ~/my_first_project + cocos server + +Now visit http://localhost:4000 and with a bit of luck you'll have something showing. + +Developing +========== + +Everything you write will be in separate JavaScript files. These will be +compiled into a single file which also includes all your other resources +including images, sound files, map files, etc. + +The entry point for the code is the file _src/main.js_ which has an +`exports.main` function that is called on startup. + +The HTML for your page is in _public/index.html_. + +Compiling your application +========================== + +You should never use the development server in production. It's very slow and +insecure. Instead you will compile your application into a single JavaScript +file. This file includes everything, you don't need to worry about hosting any +external resources such as images and tilemaps. + +To do this, on Windows double click the 'Compile project' shortcut in your +project's folder. + +On Linux and Mac OS X in your terminal run: + + cd ~/my_first_project + cocos make + +The file will be written to _build/_. You can run this through a JavaScript +minifier if you so choose. You will get a very good reduction in size if your +Web server is configured to gzip JavaScript files. + +Browser Support +=============== + +Everything should work in Firefox 3, Chrome, Safari, Opera and IE9. If that is +not the case then please file a bug report. + +Documentation +============= + +Documentation can be viewed online at + +If you wish to generate the documentation yourself you need to follow these steps. + +Download JsDoc 2.3 (or 2.4) from . + +Copy that to /usr/local/jsdoc-toolkit or wherever you like and then run: + + JSDOC_HOME=/usr/local/jsdoc-toolkit ./bin/jsdoc + +The documentation will appear in the 'docs' directory. + +License +======= + +Cocos2D JavaScript is released under the MIT license. See LICENSE for more details. + +© 2010-2011 Ryan Williams + +Links +===== + +* Twitter: [@cocos2djs](http://twitter.com/cocos2djs) +* Website: +* Documentation: +* Forum: +* Email: + + +[nodejs]: http://nodejs.org +[npm]: http://npmjs.org diff --git a/bin/Compile project.exe b/bin/Compile project.exe new file mode 100755 index 0000000..1df23d8 Binary files /dev/null and b/bin/Compile project.exe differ diff --git a/bin/Create project.exe b/bin/Create project.exe new file mode 100755 index 0000000..b5dcf64 Binary files /dev/null and b/bin/Create project.exe differ diff --git a/bin/Serve project.exe b/bin/Serve project.exe new file mode 100755 index 0000000..4b0a3f7 Binary files /dev/null and b/bin/Serve project.exe differ diff --git a/bin/cocos.bat b/bin/cocos.bat new file mode 100755 index 0000000..405050d --- /dev/null +++ b/bin/cocos.bat @@ -0,0 +1,33 @@ +@echo off +set COCOS_DIR=%~dp0.. +set UNIX_COCOS_DIR=%COCOS_DIR:\=/% + +REM There has to be a better way to do this... +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:A:=/cygdrive/a% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:B:=/cygdrive/b% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:C:=/cygdrive/c% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:D:=/cygdrive/d% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:E:=/cygdrive/e% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:F:=/cygdrive/f% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:G:=/cygdrive/g% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:H:=/cygdrive/h% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:I:=/cygdrive/i% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:J:=/cygdrive/j% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:K:=/cygdrive/k% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:L:=/cygdrive/l% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:M:=/cygdrive/m% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:N:=/cygdrive/n% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:O:=/cygdrive/o% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:P:=/cygdrive/p% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:Q:=/cygdrive/q% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:R:=/cygdrive/r% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:S:=/cygdrive/s% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:T:=/cygdrive/t% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:U:=/cygdrive/u% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:V:=/cygdrive/v% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:W:=/cygdrive/w% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:X:=/cygdrive/x% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:Y:=/cygdrive/y% +set UNIX_COCOS_DIR=%UNIX_COCOS_DIR:Z:=/cygdrive/z% + +"%COCOS_DIR%\support\node-builds\win32\node" "%UNIX_COCOS_DIR%/bin/cocos.js" %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/bin/cocos.js b/bin/cocos.js new file mode 100755 index 0000000..01495fb --- /dev/null +++ b/bin/cocos.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +var sys = require('sys'), + fs = require('fs'), + path = require('path'); + +require.paths.unshift(path.join(__dirname, '../lib')); + +if (parseInt(process.version.split('.')[1], 10) < 2) { + sys.puts('ERROR: cocos2d requires node version 0.2.x or higher, but you are using ' + process.version); + process.exit(1); +} + +var version = JSON.parse(fs.readFileSync(__dirname + '/../package.json')).version; + +sys.puts('cocos2d-javascript version ' + version); + +require('cocos2d').main(); diff --git a/bin/cocos.sh b/bin/cocos.sh new file mode 100755 index 0000000..984bf3a --- /dev/null +++ b/bin/cocos.sh @@ -0,0 +1,44 @@ +#!/bin/sh -e +# lets check if we have the submodules initialized + +if [ -h $0 ]; then + DIR=$(dirname $(readlink $0)) +else + DIR=$(dirname $0) +fi + +if which node &> /dev/null +then + # User has node installed, use that + node "$DIR/cocos.js" "$@" +else + # User doesn't have node installed, fallback to precompiled binaries + case `uname -a` in + Linux*x86_64*) + "$DIR/../support/node-builds/lin64/node" "$DIR/cocos.js" "$@" + ;; + + Linux*i686*) + "$DIR/../support/node-builds/lin32/node" "$DIR/cocos.js" "$@" + ;; + + Darwin*) + "$DIR/../support/node-builds/osx64/node" "$DIR/cocos.js" "$@" + ;; + + SunOS*) + "$DIR/../support/node-builds/sol32/node" "$DIR/cocos.js" "$@" + ;; + + CYGWIN*) + "$DIR/../support/node-builds/win32/node.exe" "$DIR/cocos.js" "$@" + ;; + + MING*) + "$DIR/../support/node-builds/win32/node.exe" "$DIR/cocos.js" "$@" + ;; + + *) echo "Unknown OS and Node isn't installed. Can't continue." + ;; + esac +fi diff --git a/bin/jsdoc.sh b/bin/jsdoc.sh new file mode 100755 index 0000000..f489244 --- /dev/null +++ b/bin/jsdoc.sh @@ -0,0 +1,10 @@ +#!/bin/sh +DIR=`dirname $0` + +java -jar "$JSDOC_HOME/jsrun.jar" "$JSDOC_HOME/app/run.js" \ + -t="$JSDOC_HOME/templates/jsdoc" \ + -r=10 \ + -v \ + -D="copyright:2011 Ryan Williams" \ + -d="docs" \ + "$DIR/../src/" diff --git a/cocos b/cocos deleted file mode 100755 index 287e810..0000000 --- a/cocos +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -if [ -f ./cocos2d/scripts/$1.py ]; then - python ./cocos2d/scripts/$1.py "$2" "$3" "$4" "$5" "$6" -elif [ -f ./scripts/$1.py ]; then - python ./scripts/$1.py "$2" "$3" "$4" "$5" "$6" -else - echo "Unknown command : $1" -fi - - diff --git a/cocos.bat b/cocos.bat deleted file mode 100644 index 83c37af..0000000 --- a/cocos.bat +++ /dev/null @@ -1,22 +0,0 @@ -@ECHO OFF - -IF EXIST ".\cocos2d\scripts\%1.py" GOTO USE_COCOS -IF EXIST ".\scripts\%1.py" GOTO USE_SCRIPTS -GOTO UNKNOWN - -:USE_COCOS -python ".\cocos2d\scripts\%1.py" "%2" "%3" "%4" "%5" "%6" - -GOTO END - -:USE_SCRIPTS -python ".\scripts\%1.py" "%2" "%3" "%4" "%5" "%6" - -GOTO END - -:UNKNOWN -ECHO "Unknown command : %1" - -GOTO END - -:END diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..37f017d --- /dev/null +++ b/install.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +if which npm &> /dev/null +then + echo "NPM is installed. You should probably install cocos2d-javascript as an npm package using this command instead:\n npm install .\n" + + read -p "Continue anyway? (y/n) : " yn + case $yn in + [Nn]* ) exit;; + [Yy]* ) break;; + * ) echo "Enter 'y' or 'n'" + esac +fi + +DIR=`dirname $0` + +read -p "Where should I install to? (/usr/local/cocos2d-javascript/) : " install_to + +if [ -z "$install_to" ] +then + install_to='/usr/local/cocos2d-javascript/' +fi + +echo "Installing to: $install_to" + +mkdir -p "$install_to" + +cd $DIR + +IFS=$'\n' +for file in `find * \( ! -regex '.*/\..*' \) -type f` +do + dst="$install_to/$file" + dst_dir=`dirname "$dst"` + if [ ! -d "$dst_dir" ] + then + mkdir -p "$dst_dir" + fi + + cp "$file" "$dst" +done + +cd - + +echo "All files copied." + +ln -s "$install_to/bin/cocos.sh" "/usr/local/bin/cocos" + +echo "Symlinked 'cocos' executable to /usr/local/bin/cocos\n" + +echo "Installation complete\n\n" + +echo "You should now be able to type 'cocos' and get a list of available commands." + + diff --git a/jsdoc b/jsdoc deleted file mode 100755 index 1069eb6..0000000 --- a/jsdoc +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -java -jar $JSDOC_HOME/jsrun.jar $JSDOC_HOME/app/run.js -t=$JSDOC_HOME/templates/jsdoc -c=jsdoc.conf -#java -jar $JSDOC_HOME/jsrun.jar $JSDOC_HOME/app/run.js -c=jsdoc.conf diff --git a/jsdoc.conf b/jsdoc.conf deleted file mode 100644 index f78ecb5..0000000 --- a/jsdoc.conf +++ /dev/null @@ -1,28 +0,0 @@ -{ - // Document the 'src' folder - _: ['src'], - - // Recursively scan to 10 levels deep - r: 10, - - // Include undocumented functions - //a: true, - - // Verbose output - v: true, - - // Include private items - //p: true, - - // Custom fields to add to documentation - D: {copyright: '2010 Ryan Williams'}, - - // Destination is 'docs' - d: 'docs', - - // Use our custom template - // XXX Moved to the cocos2d/jsdoc script - //t: '/usr/local/jsdoc-toolkit/templates/jsdoc', -} - -// vim:ft=javascript diff --git a/lib/cocos2d/commands/help.js b/lib/cocos2d/commands/help.js new file mode 100644 index 0000000..3c1ca85 --- /dev/null +++ b/lib/cocos2d/commands/help.js @@ -0,0 +1,22 @@ +/*globals require module exports process console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +var sys = require('sys'); + +exports.description = 'Show list of available commands'; +exports.run = function (opts) { + var commands = require('./'); + sys.puts('Available commands are:'); + for (var key in commands) { + if (commands.hasOwnProperty(key)) { + var command = 'cocos ' + key; + + var spaces = ''; + for (var i = 0; i < 8 - key.length; i++) { + spaces += ' '; + } + sys.puts(' ' + command + spaces + ': ' + commands[key].description); + } + } +}; diff --git a/lib/cocos2d/commands/ide.js b/lib/cocos2d/commands/ide.js new file mode 100644 index 0000000..6df7d43 --- /dev/null +++ b/lib/cocos2d/commands/ide.js @@ -0,0 +1,11 @@ +/*globals require module exports process console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +var sys = require('sys'); + +exports.description = 'Run the Cloud9 IDE'; +exports.run = function (opts) { + sys.puts('Not implemented yet'); + process.exit(1); +}; diff --git a/lib/cocos2d/commands/index.js b/lib/cocos2d/commands/index.js new file mode 100644 index 0000000..e575a33 --- /dev/null +++ b/lib/cocos2d/commands/index.js @@ -0,0 +1,7 @@ +module.exports = { + 'help': require('./help'), + 'new': require('./new'), + 'server': require('./server'), + 'make': require('./make'), + 'ide': require('./ide') +}; diff --git a/lib/cocos2d/commands/make.js b/lib/cocos2d/commands/make.js new file mode 100644 index 0000000..3e5f63b --- /dev/null +++ b/lib/cocos2d/commands/make.js @@ -0,0 +1,542 @@ +/*globals require module exports process console __dirname*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +var sys = require('sys'), + opts = require('../opts'), + fs = require('fs'), + path = require('path'), + Template = require('../template').Template, + mimetypes = require('../mimetypes'); + + +var cwd = process.cwd(); + +var OPTIONS = [ + { short: 'f', + long: 'file', + description: 'File to write output to. Overrides config file', + value: true }, + + { short: 'c', + long: 'config', + description: 'Configuration file. Default is make.json', + value: true } +]; + +mimetypes.addType('application/xml', '.tmx'); +mimetypes.addType('application/xml', '.tsx'); +mimetypes.addType('application/xml', '.plist'); + +var RESOURCE_TEMPLATE = new Template('__resources__["$resource$"] = {meta: {mimetype: "$mimetype$"}, data: $data$};'); +var REMOTE_RESOURCE_TEMPLATE = new Template('__remote_resources__["$resource$"] = {meta: {mimetype: "$mimetype$"}, data: "$data$"};'); +var TEXT_MIMETYPES = 'application/xml text/plain text/json application/json text/html'.split(' '); +var CODE_MIMETYPES = 'text/javascript application/javascript application/x-javascript'.split(' '); + + +var DEFAULT_MAKE_JSON = { + output: { + script: "cocos2d-app.js", + resources: "resources" + }, + extensions: ["js", "gif", "jpeg", "jpg", "png", "tmx", "tsx", "plist"], + ignore: null, + main_module: "main", + pack_resources: true, + resource_url: false, + paths: {} +}; +DEFAULT_MAKE_JSON.paths[path.join(__dirname, '../../../src')] = '/__builtin__'; + +/** + * Merge an number of objects together and return the result as a new object + */ +function merge() { + var o = {}; + for (var i = 0, len = arguments.length; i < len; i++) { + var obj = arguments[i]; + for (var x in obj) { + if (obj.hasOwnProperty(x)) { + o[x] = obj[x]; + } + } + } + + return o; +} + +/** + * Merges 2 objects loaded from a make.json files or simiular. + * + * @param {Object} conf1 First config + * @param {Object} conf2 Second config. Will override conf1 + * @returns Object A new object + */ +function mergeMakeConfig(conf1, conf2) { + var o = merge(conf1, conf2); + o.paths = merge(conf1.paths, conf2.paths); + return o; +} + +/** + * @memberOf cocos.commands.make + * @class Compile a cocos2d project into a single javascript file + * @param {String} [configFile=make.json] The project's config filename + */ +function Compiler(configFile) { + /** + * Resources that need copying + */ + this.remoteResources = {}; + + this.readConfig = function (configFile) { + sys.puts('Loading config: ' + configFile); + + var config = this.readJSONFile(configFile); + config = mergeMakeConfig(DEFAULT_MAKE_JSON, config); + // Set resource url to the output path + if (config.resource_url === false) { + config.resource_url = config.output.resources; + } + + // Force .js files to be packed + if (config.pack_resources instanceof Array) { + config.pack_resources.push('js'); + } else if (config.pack_resources === false) { + config.pack_resources = ['js']; + } + + this.output = config.output; + this.mainModule = config.mainModule || config.main_module; + this.extensions = config.extensions; + + return config; + }; + + this.config = this.readConfig(configFile || 'make.json'); +} +(function () /** @lends cocos.commands.make.Compiler# */{ + + /** + * Read a JSON file and clean up any comments, unquoted keys and trailing + * commas before returning the object + * + * @param {String} filename Name of the JSON file to read + * @returns {Object} The JSON object + */ + this.readJSONFile = function (filename) { + var j = fs.readFileSync(filename, 'utf8'); + + // Strip comments + j = j.replace(/\/\/.*/g, ''); + j = j.replace(/\/\*(.|[\n\r])*?\*\//mg, ''); + + // Fix unquoted keys + j = j.replace(/\{\s*(\w)/g, '{"$1'); + j = j.replace(/,(\s*)(\w)/g, ',$1"$2'); + j = j.replace(/(\w):/g, '$1":'); + + // Fix trailing comma + j = j.replace(/,\s+\}/mg, '}'); + + return JSON.parse(j); + }; + + this.__defineGetter__('appConfigFiles', function () { + if (this.appConfigFiles_) { + return this.appConfigFiles_; + } + + var configs = ['src/libs/cocos2d/config.json', 'cocos2d/src/libs/cocos2d/config.json']; + + for (var source in this.config.paths) { + if (this.config.paths.hasOwnProperty(source)) { + var dest = this.config.paths[source]; + + + var c = path.join(source, 'config.json'); + if (path.existsSync(c)) { + configs.push(c); + } + c = path.join(source, 'libs/cocos2d/config.json'); + if (path.existsSync(c)) { + configs.push(c); + } + } + } + + this.appConfigFiles_ = configs; + + return this.appConfigFiles_; + }); + + /** + * Reads all the app's config.js files and returns an of object their + * values + */ + this.__defineGetter__('appConfig', function () { + if (this.appConfig_) { + return this.appConfig_; + } + + var vals = {}, data; + for (var i = 0, len = this.appConfigFiles.length; i < len; i++) { + var config = this.appConfigFiles[i]; + if (path.existsSync(config)) { + data = this.readJSONFile(config); + vals = merge(vals, data); + } + } + + this.appConfig_ = vals; + return this.appConfig_; + }); + + /** + * Compile everything into a single script + */ + this.make = function () { + var code = this.header || ''; + code += '\n(function() {\n'; + code += 'var __main_module_name__ = ' + JSON.stringify(this.mainModule) + ';\n'; + code += 'var __resources__ = {};\n'; + code += 'var __remote_resources__ = {};\n'; + code += 'function __imageResource(data) { var img = new Image(); img.src = data; return img; };\n'; + + // Add config options + for (var key in this.appConfig) { + if (this.appConfig.hasOwnProperty(key)) { + code += 'var ' + key.toUpperCase() + ' = ' + JSON.stringify(this.appConfig[key]) + ';\n'; + } + } + + // Add all the code/images/etc + for (var source in this.config.paths) { + if (this.config.paths.hasOwnProperty(source)) { + var dest = this.config.paths[source]; + code += this.makePath(source, dest); + } + } + + var module_js = path.join(__dirname, 'module_js'); + code += fs.readFileSync(module_js, 'utf8'); + + code += '\n})();\n'; + + code += this.footer || ''; + + return code; + }; + + /** + * Compile everything at a path and return the code + * + * @param {String} source Path to compile + * @param {String} [dest=source] Output path + * @returns {String} Compiled javascript source code + */ + this.makePath = function (source, dest) { + sys.puts('Building Path: ' + source + ' => ' + dest); + + var code = ''; + var files = this.scanForFiles(source); + for (var i = 0, len = files.length; i < len; i++) { + var sourceFile = files[i]; + if (!!~this.appConfigFiles.indexOf(sourceFile)) { + continue; + } + + var destFile = this.destForSource(sourceFile), + mimetype = mimetypes.guessType(sourceFile), + ext = destFile.split('.').pop().toLowerCase(); + + + sys.puts('Building File: ' + sourceFile + ' => ' + destFile); + code += '\n'; + + // Is this a remote resource which should be loaded at runtime + // rather than be packed into the .js + var isRemote = (this.config.pack_resources === false || (this.config.pack_resources instanceof Array && !~this.config.pack_resources.indexOf(ext))); + + if (isRemote) { + this.remoteResources[sourceFile] = destFile; + code += REMOTE_RESOURCE_TEMPLATE.substitute({ + 'mimetype': mimetype, + 'resource': destFile, + 'data': path.join(this.config.resource_url, destFile) + }); + } else { + code += RESOURCE_TEMPLATE.substitute({ + 'mimetype': mimetype, + 'resource': destFile, + 'data': this.makeResource(sourceFile) + }); + } + } + + + return code; + }; + + this.destForSource = function (path) { + for (var source in this.config.paths) { + if (this.config.paths.hasOwnProperty(source)) { + var dest = this.config.paths[source]; + + // Source starts with config path + if (path.indexOf(source) === 0) { + return path.replace(source, dest).replace(/\/+/, '/'); + } + } + } + + return null; + }; + + this.sourceForDest = function (uri) { + for (var source in this.config.paths) { + if (this.config.paths.hasOwnProperty(source)) { + var dest = this.config.paths[source]; + + // Source starts with config path + if (uri.indexOf(dest) === 0) { + var realPath = path.join(source, uri.replace(dest, '').replace(/\/+/, '/')); + if (path.existsSync(realPath)) { + return realPath; + } + } + } + } + + return null; + }; + + this.makeResource = function (filename) { + var mimetype = mimetypes.guessType(filename); + + var isCode = (!!~CODE_MIMETYPES.indexOf(mimetype)), + isText = (!!~TEXT_MIMETYPES.indexOf(mimetype)), + isImage = (mimetype.split('/')[0] == 'image'); + + var data; + if (isCode) { + data = fs.readFileSync(filename, 'utf8'); + data = "function(exports, require, module, __filename, __dirname) {\n" + data + "\n}"; + } else if (isText) { + data = JSON.stringify(fs.readFileSync(filename, 'utf8')); + } else if (isImage) { + // Pack images into the file as Base64 encoded strings. + data = fs.readFileSync(filename).toString('base64'); + data = '__imageResource("data:' + mimetype + ';base64,' + data + '")'; + } else /* isBinary */ { + data = JSON.stringify(fs.readFileSync(filename).toString('base64')); + } + + return data; + }; + + this.guessMimeType = function (filename) { + return 'image/png'; + }; + + /** + * Scan for files to build and return them as an array + * + * @param {String} source Path to scan + * @returns {String[]} List of filenames + */ + this.scanForFiles = function (source) { + + if (!path.existsSync(source)) { + console.log('ERROR: Unable to find path: ', source); + return []; + } + + var foundFiles = []; + + // If given a file rather than a directory they just return that + if (fs.statSync(source).isFile()) { + return [source]; + } + + // Find all files in directory + var files = fs.readdirSync(source); + for (var i = 0, len = files.length; i < len; i++) { + var file = files[i]; + // Skip hidden files + if (file[0] == '.') { + continue; + } + + var fullPath = path.join(source, file); + + if (fs.statSync(fullPath).isFile()) { + // If extension isn't in our list then skip file + if (this.extensions && this.extensions.length && !~this.extensions.indexOf(path.extname(file).slice(1))) { + continue; + } + + foundFiles.push(fullPath); + } else { + // Directory + foundFiles = foundFiles.concat(this.scanForFiles(fullPath)); + } + + } + + return foundFiles; + }; +}).call(Compiler.prototype); + +exports.Compiler = Compiler; + +function mkdir(dir, mode) { + mode = mode || 511; // Octal = 0777; + + if (dir[0] != '/') { + dir = path.join(cwd, dir); + } + + var paths = [dir]; + var d = dir; + while ((d = path.dirname(d)) && d != '/') { + paths.unshift(d); + } + + for (var i = 0, len = paths.length; i < len; i++) { + var p = paths[i]; + if (!path.existsSync(p)) { + fs.mkdirSync(p, mode); + } + } +} + + +function copyFolder(src, dst) { + if (fs.statSync(src).isDirectory()) { + mkdir(dst); + sys.puts("Created directory: " + dst); + + var files = fs.readdirSync(src); + for (var i = 0, len = files.length; i < len; i++) { + var file = files[i]; + if (file[0] == '.') { + // Skip hidden files + continue; + } + + var dstFile = path.join(dst, path.basename(file)); + copyFolder(path.join(src, file), dstFile); + } + } else { + sys.pump(fs.createReadStream(src), fs.createWriteStream(dst)); + sys.puts("Copied file: " + dst); + } +} + +/** + * @see https://gist.github.com/563078/afa6c25facaf857712c6847c0bdc748cb6476f93 + */ + +function copytree(src, dst) { + if(!path.existsSync(src)) { + throw new Error(src + ' does not exists. Nothing to be copied'); + } + + if(!fs.statSync(src).isDirectory()) { + throw new Error(src + ' must be a directory'); + } + + var filenames = fs.readdirSync(src); + var basedir = src; + + if(!path.existsSync(dst)) { + fs.mkdirSync(dst, parseInt('0755', 8)); + } + var readNext = function(){ + if (!filenames.length) return; + var filename = filenames.shift(); + console.log(filename); + var file = basedir + '/' + filename; + var newdst = dst + '/' + filename; + + if(fs.statSync(file).isDirectory()) { + copytree(file, newdst); + readNext(); + } else { + copytree.count++; + var reader = fs.createReadStream(file); + var writer = fs.createWriteStream(newdst); + writer.addListener('close', function(){ + copytree.count--; + readNext(); + }); + sys.pump(reader, writer); + } + } + readNext(); + while (filenames.length && copytree.count < copytree.limit) readNext(); +} +copytree.limit = 2; +copytree.count = 0; + +exports.description = 'Compile a cocos2d project into a single javascript file'; +exports.run = function () { + opts.parse(OPTIONS, true); + + var config = opts.get('config') || 'make.json', + compiler = new Compiler(config), + output = opts.get('file') || compiler.output, + outputDir = 'build/'; + + var code = compiler.make(); + + function cp(src, dst, callback) { + mkdir(path.dirname(dst)); + + var reader = fs.createReadStream(src), + writer = fs.createWriteStream(dst); + + writer.addListener('close', function () { callback(); }); + + sys.pump(reader, writer); + } + + var files = []; + function next() { + if (!files.length) { + return; + } + var names = files.shift(); + cp(names[0], names[1], next); + } + + if (output) { + var scriptOutput = path.join(outputDir, output.script || output); + var resourceOutput = path.join(outputDir, output.resources) || path.join(path.dirname(scriptOutput), 'resources'); + + // Write script + sys.puts("Writing script to: " + scriptOutput); + mkdir(path.dirname(scriptOutput)); + fs.writeFileSync(scriptOutput, code, 'utf8'); + + // Copy public folder + copytree('public', 'build'); + + // Copy resources + sys.puts("Copying resources to: " + resourceOutput); + mkdir(resourceOutput); + + for (var source in compiler.remoteResources) { + if (compiler.remoteResources.hasOwnProperty(source)) { + var dest = path.join(resourceOutput, compiler.remoteResources[source]); + files.push([source, dest]); + } + } + + next(); + + } else { + sys.puts(code); + } +}; diff --git a/scripts/module.js b/lib/cocos2d/commands/module_js similarity index 59% rename from scripts/module.js rename to lib/cocos2d/commands/module_js index 13ea1d7..5d843be 100644 --- a/scripts/module.js +++ b/lib/cocos2d/commands/module_js @@ -1,10 +1,31 @@ +/*globals module exports resource require window Module __main_module_name__ __resources__*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + function resource(path) { - return window.__resources__[path].data; + // Check for packed resource + var r = __resources__[path]; + if (r) { + return r.data; + } + + // Check for remote resource + r = __remote_resources__[path]; + if (r) { + // Load remote image + if (r.meta.mimetype.split('/')[0] == 'image') { + return require('cocos2d').RemoteImage.create({url: r.data, path: path}); + } else { + return require('cocos2d').RemoteResource.create({url: r.data, path: path}); + } + } + + throw("Unable to find resource: " + path.toString()); } -(function() { +(function () { var process = {}; - var modulePaths = ['/', '/libs']; + var modulePaths = ['/__builtin__', '/__builtin__/libs', '/libs', '/']; var path; // Will be loaded further down @@ -62,6 +83,13 @@ function resource(path) { //console.log('Loading module: ', filename); var module = new Module(filename, parent); + + // Assign main module to process + if (request == __main_module_name__ && !process.mainModule) { + process.mainModule = module; + } + + // Run all the code in the module module._initialize(filename); return module; @@ -85,7 +113,7 @@ function resource(path) { this.dirname = null; } - Module.prototype._initialize = function(filename) { + Module.prototype._initialize = function (filename) { var module = this; function require(request) { return loadModule(request, module).exports; @@ -103,30 +131,39 @@ function resource(path) { require.paths = modulePaths; require.main = process.mainModule; - window.__resources__[this.filename].data.apply(this.exports, [this.exports, require, this, this.filename, this.dirname]) + __resources__[this.filename].data.apply(this.exports, [this.exports, require, this, this.filename, this.dirname]); return this; - } + }; // Manually load the path module because we need it to load other modules - path = (new Module('path'))._initialize('/path.js').exports; + path = (new Module('path'))._initialize('/__builtin__/path.js').exports; + var util = loadModule('util').exports; + util.ready(function () { + // Populate globals + var globals = loadModule('global').exports; + for (var x in globals) { + if (globals.hasOwnProperty(x)) { + window[x] = globals[x]; + } + } - // Populate globals - var globals = loadModule('global').exports; - for (var x in globals) { - window[x] = globals[x]; - } + // Add a global require. Useful in the debug console. + window.require = function require(request, parent) { + return loadModule(request, parent).exports; + }; + window.require.paths = modulePaths; - var util = loadModule('util').exports; - util.ready(function() { process.mainModule = loadModule(__main_module_name__); - }); - // Add a global require. Useful in the debug console. - window.require = function require(request, parent) { - return loadModule(request, parent).exports; - } - window.require.paths = modulePaths; - window.require.main = process.mainModule; + window.require.main = process.mainModule; + + if (process.mainModule.exports.main) { + process.mainModule.exports.main(); + } + + }); })(); + +// vim:ft=javascript diff --git a/lib/cocos2d/commands/new.js b/lib/cocos2d/commands/new.js new file mode 100644 index 0000000..42df0a1 --- /dev/null +++ b/lib/cocos2d/commands/new.js @@ -0,0 +1,102 @@ +/*globals require module exports process console __dirname*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +var sys = require('sys'), + opts = require('../opts'), + path = require('path'), + Template = require('../template').Template, + fs = require('fs'); + +var SKELETON_PATH = path.join(__dirname, '../skeleton'); + +var ARGS = [ + {name: 'APP_PATH', required: true} +]; + + +function camelCase(str, upperFirst) { + if (upperFirst) { + return str.replace(/(^.|[_\s]+[a-zA-Z])/g, function (s) { + return s.replace(/[_\s]/g, '').toUpperCase(); + }); + } else { + return str.replace(/_+[a-zA-Z]/g, function (s) { + return s.replace(/[_\s]/g, '').toUpperCase(); + }); + } +} +function snakeCase(str) { + str = str.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2'); + str = str.replace(/([a-z\d])([A-Z])/g, '$1_$2'); + str = str.replace('-', '_'); + + return str.toLowerCase(); +} +function titleize(str) { + return str.replace(/(^.|_+[a-zA-Z])/g, function (s) { + return s.replace(/[_\s]/g, ' ').toUpperCase(); + }); +} + +function mkdir(dir, mode) { + mode = mode || 511; // Octal = 0777; + var paths = [dir]; + var d = dir; + while ((d = path.dirname(d)) && d != '/') { + paths.unshift(d); + } + + for (var i = 0, len = paths.length; i < len; i++) { + var p = paths[i]; + if (!path.existsSync(p)) { + fs.mkdirSync(p, mode); + } + } +} + +exports.description = 'Create a new cocos2d project'; +exports.run = function () { + opts.parse([], ARGS, true); + + var fullPath = path.normalize(path.join(process.cwd(), opts.arg('APP_PATH'))), + basename = path.basename(fullPath), + classname = camelCase(basename, true), + filename = snakeCase(classname), + appname = titleize(filename); + + mkdir(fullPath); + + sys.puts("Writing new project named '" + classname + "' to: " + fullPath); + + function copyTemplate(src, dst) { + if (fs.statSync(src).isDirectory()) { + mkdir(dst); + sys.puts("Created Directory: " + dst); + + var files = fs.readdirSync(src); + for (var i = 0, len = files.length; i < len; i++) { + var file = files[i]; + if (file[0] == '.') { + // Skip hidden files + continue; + } + + var dstFile = path.join(dst, path.basename(file)); + copyTemplate(path.join(src, file), dstFile); + } + } else { + var tmp = new Template(fs.readFileSync(src, 'utf8')); + var data = tmp.substitute({ + appname: appname, + classname: classname, + filename: filename, + basename: basename + }); + fs.writeFileSync(dst, data, 'utf8'); + sys.puts("Created File: " + dst); + } + } + + copyTemplate(SKELETON_PATH, fullPath); +}; diff --git a/lib/cocos2d/commands/server.js b/lib/cocos2d/commands/server.js new file mode 100644 index 0000000..8a84f87 --- /dev/null +++ b/lib/cocos2d/commands/server.js @@ -0,0 +1,98 @@ +/*globals require module exports process console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +var sys = require('sys'), + http = require('http'), + qs = require('querystring'), + url = require('url'), + path = require('path'), + fs = require('fs'), + opts = require('../opts'), + mimetypes = require('../mimetypes'), + Compiler = require('./make').Compiler; + + +var options = [ + { short: 'u', + long: 'url', + description: 'URL to serve the JavaScript as. Default is output defined in the config file', + value: true }, + + { short: 'c', + long: 'config', + description: 'Configuration file. Default is make.json', + value: true }, + + { short: 'h', + long: 'host', + description: 'Hostname or IP address to listen on. Default is localhost', + value: true }, + + { short: 'p', + long: 'port', + description: 'Port to listen on. Default is 4000', + value: true } +]; + +exports.description = 'Run the cocos2d development web server'; +exports.run = function () { + opts.parse(options, true); + var host = opts.get('host') || 'localhost', + port = opts.get('port') || 4000, + config = opts.get('config') || 'make.json', + compiler = new Compiler(config), + output = opts.get('url') || compiler.output.script || compiler.output; + + function resourcePath(filename) { + return compiler.sourceForDest(filename) + } + + + http.createServer(function (req, res) { + var uri = url.parse(req.url, true); + + if (uri.pathname == '/') { + uri.pathname = '/index.html'; + } + + // Serve app code + if (uri.pathname == '/' + output || uri.pathname == output.replace(/^\/?public/, '')) { + var code = compiler.make(); + res.writeHead(200, {'Content-Type': 'text/javascript'}); + res.end(code); + } else { + var publicFilename = path.join(process.cwd(), 'public', uri.pathname); + // resource paths are prefixed with '/resources' + var resourceFilename = qs.unescape(uri.pathname.replace(/^\/resources/, '')); + sys.puts('Requested:' + resourceFilename); + + // If file exists in public folder, server that + if (path.existsSync(publicFilename)) { + sys.puts("Serving public file: " + publicFilename); + + var mimetype = mimetypes.guessType(uri.pathname); + res.writeHead(200, {'Content-Type': mimetype}); + res.end(fs.readFileSync(publicFilename)); + } + + // Else if file is a resource in the app, server that + else if ((resourceFilename = resourcePath(resourceFilename))) { + sys.puts("Serving resource file: " + resourceFilename); + + var mimetype = mimetypes.guessType(uri.pathname); + res.writeHead(200, {'Content-Type': mimetype}); + res.end(fs.readFileSync(resourceFilename)); + } + + // File not found + else { + sys.puts("File not found: " + uri.pathname); + res.writeHead(404, 'File not found'); + res.end('File not found'); + } + } + }).listen(parseInt(port, 10), host); + + sys.puts('Point your browser to http://' + host + ':' + port + '/'); +}; diff --git a/lib/cocos2d/index.js b/lib/cocos2d/index.js new file mode 100644 index 0000000..ce7fe26 --- /dev/null +++ b/lib/cocos2d/index.js @@ -0,0 +1,22 @@ +/*globals require module exports process console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +var sys = require('sys'), + commands = require('./commands'); + +exports.main = function (opts) { + var cmd = process.argv[2]; + + if (!cmd) { + cmd = 'help'; + } + + if (!commands[cmd]) { + sys.puts('Unknown command: ' + cmd); + sys.puts('Run "cocos help" for a list of available commands'); + process.exit(1); + } + + commands[cmd].run(process.argv.slice(3)); +}; diff --git a/lib/cocos2d/mime.types b/lib/cocos2d/mime.types new file mode 100644 index 0000000..022fded --- /dev/null +++ b/lib/cocos2d/mime.types @@ -0,0 +1,1070 @@ +# This is a comment. I love comments. + +# This file controls what Internet media types are sent to the client for +# given file extension(s). Sending the correct media type to the client +# is important so they know how to handle the content of the file. +# Extra types can either be added here or by using an AddType directive +# in your config files. For more information about Internet media types, +# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type +# registry is at . + +# MIME type Extensions +application/activemessage +application/andrew-inset ez +application/applefile +application/atom+xml atom +application/atomcat+xml atomcat +application/atomicmail +application/atomsvc+xml atomsvc +application/auth-policy+xml +application/batch-smtp +application/beep+xml +application/cals-1840 +application/ccxml+xml ccxml +application/cellml+xml +application/cnrp+xml +application/commonground +application/conference-info+xml +application/cpl+xml +application/csta+xml +application/cstadata+xml +application/cybercash +application/davmount+xml davmount +application/dca-rft +application/dec-dx +application/dialog-info+xml +application/dicom +application/dns +application/dvcs +application/ecmascript ecma +application/edi-consent +application/edi-x12 +application/edifact +application/epp+xml +application/eshop +application/fastinfoset +application/fastsoap +application/fits +application/font-tdpfr pfr +application/h224 +application/http +application/hyperstudio stk +application/iges +application/im-iscomposing+xml +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/javascript js +application/json json +application/kpml-request+xml +application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc mrc +application/mathematica ma nb mb +application/mathml+xml mathml +application/mbms-associated-procedure-description+xml +application/mbms-deregister+xml +application/mbms-envelope+xml +application/mbms-msk+xml +application/mbms-msk-response+xml +application/mbms-protection-description+xml +application/mbms-reception-report+xml +application/mbms-register+xml +application/mbms-register-response+xml +application/mbms-user-service-description+xml +application/mbox mbox +application/media_control+xml +application/mediaservercontrol+xml mscml +application/mikey +application/moss-keys +application/moss-signature +application/mosskey-data +application/mosskey-request +application/mp4 mp4s +application/mpeg4-generic +application/mpeg4-iod +application/mpeg4-iod-xmt +application/msword doc dot +application/mxf mxf +application/nasdata +application/news-transmission +application/nss +application/ocsp-request +application/ocsp-response +application/octet-stream bin dms lha lzh class so iso dmg dist distz pkg bpk dump elc scpt dmgpart +application/oda oda +application/oebps-package+xml +application/ogg ogx +application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +application/pidf+xml +application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/poc-settings+xml +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww cww +application/prs.nprend +application/prs.plucker +application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +application/riscos +application/rlmi+xml +application/rls-services+xml rs +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/rtx +application/samlassertion+xml +application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/set-payment +application/set-payment-initiation setpay +application/set-registration +application/set-registration-initiation setreg +application/sgml +application/sgml-open-catalog +application/shf+xml shf +application/sieve +application/simple-filter+xml +application/simple-message-summary +application/simplesymbolcontainer +application/slate +application/smil +application/smil+xml smi smil +application/soap+fastinfoset +application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/ssml+xml ssml +application/timestamp-query +application/timestamp-reply +application/tve-trigger +application/ulpfec +application/vemmi +application/vividence.scriptfile +application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp.sms +application/vnd.3gpp2.bcmcsinfo+xml +application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.aether.imp +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.arastra.swi swi +application/vnd.audiograph aep +application/vnd.autopackage +application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.cab-jscript +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.commerce-battelle +application/vnd.commonspace csp cst +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.ctct.ws+xml +application/vnd.cups-pdf +application/vnd.cups-postscript +application/vnd.cups-ppd ppd +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.curl curl +application/vnd.cybank +application/vnd.data-vision.rdz rdz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.dvb.esgcontainer +application/vnd.dvb.ipdcesgaccess +application/vnd.dvb.iptv.alfec-base +application/vnd.dvb.iptv.alfec-enhancement +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart mag +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.fdf fdf +application/vnd.ffsns +application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.art-ex +application/vnd.fujixerox.art4 +application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.hzn-3d-crossword x3d +application/vnd.ibm.afplinedata +application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.informedcontrol.rms+xml +application/vnd.intercon.formnet xpw xpx +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.iptc.g2.conceptitem+xml +application/vnd.iptc.g2.knowledgeitem+xml +application/vnd.iptc.g2.newsitem+xml +application/vnd.iptc.g2.packageitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.jam jam +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.marlin.drm.actiontoken+xml +application/vnd.marlin.drm.conftoken+xml +application/vnd.marlin.drm.license+xml +application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-asf asf +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-project mpp mpt +application/vnd.ms-tnef +application/vnd.ms-wmdrm.lic-chlg-req +application/vnd.ms-wmdrm.lic-resp +application/vnd.ms-wmdrm.meter-chlg-req +application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.msign +application/vnd.multiad.creator +application/vnd.multiad.creator.cif +application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.ncd.control +application/vnd.ncd.reference +application/vnd.nervana +application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.catalogs +application/vnd.nokia.conml+wbxml +application/vnd.nokia.conml+xml +application/vnd.nokia.isds-radio-presets +application/vnd.nokia.iptv.config+xml +application/vnd.nokia.landmark+wbxml +application/vnd.nokia.landmark+xml +application/vnd.nokia.landmarkcollection+xml +application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.ncd +application/vnd.nokia.pcd+wbxml +application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template otf +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master otm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.obn +application/vnd.olpc-sugar xo +application/vnd.oma-scws-config +application/vnd.oma-scws-http-request +application/vnd.oma-scws-http-response +application/vnd.oma.bcast.associated-procedure-parameter+xml +application/vnd.oma.bcast.drm-trigger+xml +application/vnd.oma.bcast.imd+xml +application/vnd.oma.bcast.ltkm +application/vnd.oma.bcast.notification+xml +application/vnd.oma.bcast.provisioningtrigger +application/vnd.oma.bcast.sgboot +application/vnd.oma.bcast.sgdd+xml +application/vnd.oma.bcast.sgdu +application/vnd.oma.bcast.simple-symbol-container +application/vnd.oma.bcast.smartcard-trigger+xml +application/vnd.oma.bcast.sprov+xml +application/vnd.oma.bcast.stkm +application/vnd.oma.dcd +application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +application/vnd.oma.drm.risd+xml +application/vnd.oma.group-usage-list+xml +application/vnd.oma.poc.detailed-progress-report+xml +application/vnd.oma.poc.final-report+xml +application/vnd.oma.poc.groups+xml +application/vnd.oma.poc.invocation-descriptor+xml +application/vnd.oma.poc.optimized-progress-report+xml +application/vnd.oma.xcap-directory+xml +application/vnd.omads-email+xml +application/vnd.omads-file+xml +application/vnd.omads-folder+xml +application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +application/vnd.osa.netdeploy +application/vnd.osgi.dp dp +application/vnd.otps.ct-kip+xml +application/vnd.palm prc pdb pqa oprc +application/vnd.paos.xml +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.pwg-multiplexed +application/vnd.pwg-xhtml-print+xml +application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +application/vnd.rapid +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml +application/vnd.renlearn.rlprint +application/vnd.rn-realmedia rm +application/vnd.route66.link66+xml link66 +application/vnd.ruckus.download +application/vnd.s3sms +application/vnd.sbm.mid2 +application/vnd.scribus +application/vnd.sealed.3df +application/vnd.sealed.csf +application/vnd.sealed.doc +application/vnd.sealed.eml +application/vnd.sealed.mht +application/vnd.sealed.net +application/vnd.sealed.ppt +application/vnd.sealed.tiff +application/vnd.sealed.xls +application/vnd.sealedmedia.softseal.html +application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +application/vnd.software602.filler.form+xml +application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.street-stream +application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +application/vnd.swiftview-ics +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.truedoc +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx vcx +application/vnd.vd-study +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +application/vnd.vividence.scriptfile +application/vnd.vsf vsf +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wfa.wsc +application/vnd.wmc +application/vnd.wmf.bootstrap +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +application/vnd.wv.csp+wbxml +application/vnd.wv.csp+xml +application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.xmi+xml +application/vnd.xmpie.cpkg +application/vnd.xmpie.dpkg +application/vnd.xmpie.plan +application/vnd.xmpie.ppkg +application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/watcherinfo+xml +application/whoispp-query +application/whoispp-response +application/winhlp hlp +application/wita +application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-ace-compressed ace +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cdlink vcd +application/x-chat chat +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-director dcr dir dxr fgd +application/x-dvi dvi +application/x-futuresplash spl +application/x-gtar gtar +application/x-gzip +application/x-hdf hdf +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-stuffit sit +application/x-stuffitx sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-texinfo texinfo texi +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x400-bp +application/xcap-att+xml +application/xcap-caps+xml +application/xcap-el+xml +application/xcap-error+xml +application/xcap-ns+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +application/xml xml xsl +application/xml-dtd dtd +application/xml-external-parsed-entity +application/xmpp+xml +application/xop+xml xop +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/zip zip +audio/32kadpcm +audio/3gpp +audio/3gpp2 +audio/ac3 +audio/amr +audio/amr-wb +audio/amr-wb+ +audio/asc +audio/basic au snd +audio/bv16 +audio/bv32 +audio/clearmode +audio/cn +audio/dat12 +audio/dls +audio/dsr-es201108 +audio/dsr-es202050 +audio/dsr-es202211 +audio/dsr-es202212 +audio/dvi4 +audio/eac3 +audio/evrc +audio/evrc-qcp +audio/evrc0 +audio/evrc1 +audio/evrcb +audio/evrcb0 +audio/evrcb1 +audio/evrcwb +audio/evrcwb0 +audio/evrcwb1 +audio/g722 +audio/g7221 +audio/g723 +audio/g726-16 +audio/g726-24 +audio/g726-32 +audio/g726-40 +audio/g728 +audio/g729 +audio/g7291 +audio/g729d +audio/g729e +audio/gsm +audio/gsm-efr +audio/ilbc +audio/l16 +audio/l20 +audio/l24 +audio/l8 +audio/lpc +audio/midi mid midi kar rmi +audio/mobile-xmf +audio/mp4 mp4a +audio/mp4a-latm m4a m4p +audio/mpa +audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +audio/mpeg4-generic +audio/ogg oga ogg spx +audio/parityfec +audio/pcma +audio/pcmu +audio/prs.sid +audio/qcelp +audio/red +audio/rtp-enc-aescm128 +audio/rtp-midi +audio/rtx +audio/smv +audio/smv0 +audio/smv-qcp +audio/sp-midi +audio/t140c +audio/t38 +audio/telephone-event +audio/tone +audio/ulpfec +audio/vdvi +audio/vmr-wb +audio/vnd.3gpp.iufp +audio/vnd.4sb +audio/vnd.audiokoz +audio/vnd.celp +audio/vnd.cisco.nse +audio/vnd.cmles.radio-events +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds eol +audio/vnd.dlna.adts +audio/vnd.dolby.mlp +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +audio/vnd.everad.plj +audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +audio/vnd.nokia.mobile-xmf +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.sealedmedia.softseal.mpeg +audio/vnd.vmx.cvsd +audio/vorbis +audio/vorbis-config +audio/wav wav +audio/x-aiff aif aiff aifc +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +audio/x-wav wav +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +chemical/x-pdb pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +image/fits +image/g3fax g3 +image/gif gif +image/ief ief +image/jp2 jp2 +image/jpeg jpeg jpg jpe +image/jpm +image/jpx +image/naplps +image/pict pict pic pct +image/png png +image/prs.btif btif +image/prs.pti +image/svg+xml svg svgz +image/t38 +image/tiff tiff tif +image/tiff-fx +image/vnd.adobe.photoshop psd +image/vnd.cns.inf2 +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.globalgraphics.pgb +image/vnd.microsoft.icon +image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.net-fpx npx +image/vnd.sealed.png +image/vnd.sealedmedia.softseal.gif +image/vnd.sealedmedia.softseal.jpg +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/x-cmu-raster ras +image/x-cmx cmx +image/x-icon ico +image/x-macpaint pntg pnt mac +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-quicktime qtif qti +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/cpim +message/delivery-status +message/disposition-notification +message/external-body +message/global +message/global-delivery-status +message/global-disposition-notification +message/global-headers +message/http +message/news +message/partial +message/rfc822 eml mime +message/s-http +message/sip +message/sipfrag +message/tracking-status +message/vnd.si.simp +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf dwf +model/vnd.flatland.3dml +model/vnd.gdl gdl +model/vnd.gs.gdl +model/vnd.gtw gtw +model/vnd.moml+xml +model/vnd.mts mts +model/vnd.parasolid.transmit.binary +model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/calendar ics ifb +text/css css +text/csv csv +text/directory +text/dns +text/enriched +text/html html htm +text/parityfec +text/plain txt text conf def list log in +text/prs.fallenstein.rst +text/prs.lines.tag dsc +text/red +text/rfc822-headers +text/richtext rtx +text/rtf +text/rtp-enc-aescm128 +text/rtx +text/sgml sgml sgm +text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/ulpfec +text/uri-list uri uris urls +text/vnd.abc +text/vnd.curl +text/vnd.dmclientscript +text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.iptc.newsml +text/vnd.iptc.nitf +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.net2phone.commcenter.command +text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +text/vnd.trolltech.linguist +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-pascal p pas +text/x-java-source java +text/x-setext etx +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +text/xml +text/xml-external-parsed-entity +video/3gpp 3gp +video/3gpp-tt +video/3gpp2 3g2 +video/bmpeg +video/bt656 +video/celb +video/dv +video/h261 h261 +video/h263 h263 +video/h263-1998 +video/h263-2000 +video/h264 h264 +video/jpeg jpgv +video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +video/mp1s +video/mp2p +video/mp2t +video/mp4 mp4 mp4v mpg4 m4v +video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +video/mpeg4-generic +video/mpv +video/nv +video/ogg ogv +video/parityfec +video/pointer +video/quicktime qt mov +video/raw +video/rtp-enc-aescm128 +video/rtx +video/smpte292m +video/ulpfec +video/vc1 +video/vnd.cctv +video/vnd.dlna.mpeg-tts +video/vnd.fvt fvt +video/vnd.hns.video +video/vnd.iptvforum.1dparityfec-1010 +video/vnd.iptvforum.1dparityfec-2005 +video/vnd.iptvforum.2dparityfec-1010 +video/vnd.iptvforum.2dparityfec-2005 +video/vnd.iptvforum.ttsavc +video/vnd.iptvforum.ttsmpeg2 +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +video/vnd.nokia.interleaved-multimedia +video/vnd.nokia.videovoip +video/vnd.objectvideo +video/vnd.sealed.mpeg1 +video/vnd.sealed.mpeg4 +video/vnd.sealed.swf +video/vnd.sealedmedia.softseal.mov +video/vnd.vivo viv +video/x-dv dv dif +video/x-fli fli +video/x-ms-asf asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice diff --git a/lib/cocos2d/mimetypes.js b/lib/cocos2d/mimetypes.js new file mode 100644 index 0000000..c1ac913 --- /dev/null +++ b/lib/cocos2d/mimetypes.js @@ -0,0 +1,69 @@ +var fs = require('fs'), + path = require('path'); + +var typesMap = {}, + typesMapInv = {}; + +exports.knowntypes = ['/etc/mime.types', + '/etc/httpd/mime.types', + '/etc/httpd/conf/mime.types', + '/etc/apache/mime.types', + '/etc/apache2/mime.types', + '/usr/local/etc/httpd/conf/mime.types', + '/usr/local/lib/netscape/mime.types', + '/usr/local/etc/httpd/conf/mime.types', + '/usr/local/etc/mime.types', + path.join(__dirname, 'mime.types')]; + +exports.guessType = function(url) { + return typesMap[path.extname(url)]; +}; + + +function addType(type, ext) { + typesMap[ext] = type.trim(); + if (!typesMapInv[type]) { + typesMapInv[type] = []; + } + if (!~typesMapInv[type].indexOf(ext)) { + typesMapInv[type].push(ext); + } +} + +exports.addType = addType; + +/** + * Read a single mime.types-format file + */ +function read(file) { + var data = fs.readFileSync(file, 'ascii'); + // Strip comments + data = data.replace(/#.*/g, ''); + var lines = data.split('\n'); + for (var i = 0, len = lines.length; i < len; i++) { + var line = lines[i].trim(); + if (!line) { + continue; + } + + var words = line.split(/\s/), + type = words.shift(), + suffixes = words; + + for (var j = 0, jen = suffixes.length; j < jen; j++) { + var suff = suffixes[j].trim(); + if (!suff) { + continue; + } + + addType(type, '.' + suff); + } + } +} + +for (var i = 0, len = exports.knowntypes.length; i < len; i++) { + var typeFile = exports.knowntypes[i]; + if (path.existsSync(typeFile)) { + read(typeFile); + } +} diff --git a/lib/cocos2d/opts.js b/lib/cocos2d/opts.js new file mode 100644 index 0000000..2559d3a --- /dev/null +++ b/lib/cocos2d/opts.js @@ -0,0 +1,276 @@ +/*************************************************************************** +Author : Joey Mazzarelli +Email : mazzarelli@gmail.com +Homepage : http://joey.mazzarelli.com/js-opts +Source : http://bitbucket.org/mazzarell/js-opts/ +License : Simplified BSD License +Version : 1.0 + +Copyright 2010 Joey Mazzarelli. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY JOEY MAZZARELLI 'AS IS' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL JOEY MAZZARELLI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of Joey Mazzarelli. +***************************************************************************/ + +var path = require('path'); + +var puts = console.log + , values = {} + , args = {} + , argv = [] + , errors = [] + , descriptors = {opts:[], args:[]}; + +/** + * Get some version info out of it + */ +exports.version = '1.2.1'; + +/** + * Add a set of option descriptors, not yet ready to be parsed. + * See exports.parse for description of options object + * + * Additionally, it takes a namespace as an argument, useful for + * building options for a library in addition to the main app. + */ +exports.add = function (options, namespace) { + for (var i=0; i or by including the option; + * { + * long : 'help', + * description : 'Show this help message', + * callback : require('./opts').help, + * } + * + * ===== Arguments Docs ===== + * Arguments are different than options, and simpler. They typically come + * after the options, but the library really doesn't care. Each argument + * can have the form of: + * { + * name : 'script', + * required : true, // default false + * callback : function (value) { ... }, + * } + */ +exports.parse = function (options, params, help) { + + if (params === true) { + help = true; + params = []; + } else if (!params) { + params = []; + } else { + for (var i=0; i + + + + + $appname$ + + + +

$appname$

+
$appname$ is loading...
+ + diff --git a/lib/cocos2d/skeleton/src/main.js b/lib/cocos2d/skeleton/src/main.js new file mode 100644 index 0000000..ac04e93 --- /dev/null +++ b/lib/cocos2d/skeleton/src/main.js @@ -0,0 +1,43 @@ +// Import the cocos2d module +var cocos = require('cocos2d'), +// Import the geometry module + geo = require('geometry'); + +// Create a new layer +var $classname$ = cocos.nodes.Layer.extend({ + init: function() { + // You must always call the super class version of init + $classname$.superclass.init.call(this); + + // Get size of canvas + var s = cocos.Director.get('sharedDirector').get('winSize'); + + // Create label + var label = cocos.nodes.Label.create({string: '$appname$', fontName: 'Arial', fontSize: 76}); + + // Add label to layer + this.addChild({child: label, z:1}); + + // Position the label in the centre of the view + label.set('position', geo.ccp(s.width / 2, s.height / 2)); + } +}); + +exports.main = function() { + // Initialise application + + // Get director + var director = cocos.Director.get('sharedDirector'); + + // Attach director to our
element + director.attachInView(document.getElementById('$filename$_app')); + + // Create a scene + var scene = cocos.nodes.Scene.create(); + + // Add our layer to the scene + scene.addChild({child: $classname$.create()}); + + // Run the scene + director.runWithScene(scene); +}; diff --git a/lib/cocos2d/template.js b/lib/cocos2d/template.js new file mode 100644 index 0000000..bfabba0 --- /dev/null +++ b/lib/cocos2d/template.js @@ -0,0 +1,25 @@ +/*globals module exports require process*/ +/*jslint undef: true, strict: true, white: true, newcap: true, indent: 4 */ +"use strict"; + +function Template(str) { + this.string = str; +} +(function () { + this.substitute = function (subs) { + var newStr = this.string; + for (var key in subs) { + if (subs.hasOwnProperty(key)) { + newStr = newStr.replace(new RegExp('\\$' + key + '\\$', 'g'), subs[key]); + } + } + + return newStr; + }; + + this.toString = function () { + return this.string; + }; +}).call(Template.prototype); + +exports.Template = Template; diff --git a/make.js b/make.js deleted file mode 100644 index 8bc143b..0000000 --- a/make.js +++ /dev/null @@ -1,14 +0,0 @@ -{ - "output": "public/tests.js", - "extensions": ["js", "gif", "jpeg", "jpg", "png", "tmx", "tsx", "plist"], - "ignore": null, - "main_module": "main", - - "paths": { - "src" : "/", - "tests/commonjs/tests/" : "/commonjs/", - "tests/cocos2d/" : "/cocos2d/", - "tests/commonjs.js": "/commonjs.js", - "tests/main.js": "/main.js" - } -} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8547950 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "cocos2d", + "author": "Ryan Williams ", + "description": "Port of the Cocos2D graphics engine to HTML5", + "version": "0.2.0-alpha", + "homepage": "http://cocos2d-javascript.org/", + + "engines": { + "node": ">= 0.4.0" + }, + + "repository": { + "type" : "git" , + "url" : "https://github.com/ryanwilliams/cocos2d-javascript.git" + }, + + "bin": { + "cocos": "./bin/cocos.js" + }, + + "licenses": [{ + "type": "MIT", + "url": "https://github.com/ryanwilliams/cocos2d-javascript/blob/master/LICENSE" + }] +} diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 2809892..0000000 --- a/public/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - Cocos2D -- Tests - - - -

Tests

-

Select a test suite to run:

- -
- - diff --git a/scripts/make.py b/scripts/make.py deleted file mode 100755 index b4ddc2e..0000000 --- a/scripts/make.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env python - -from optparse import OptionParser -from cStringIO import StringIO -import re, os, base64, mimetypes, codecs -try: - import json -except: - import simplejson as json - -TEXT_MIMETYPES = 'application/xml text/plain text/json application/json text/html'.split(' ') -CODE_MIMETYPES = 'text/javascript application/javascript application/x-javascript'.split(' ') - -IMAGE_RESOURCE_TEMPLATE = u'\nwindow.__resources__["%s"] = {meta: {mimetype: "%s"}, data: __imageResource("data:%s;base64,%s")};\n' -BINARY_RESOURCE_TEMPLATE = u'\nwindow.__resources__["%s"] = {meta: {mimetype: "%s"}, data: "%s"};\n' -TEXT_RESOURCE_TEMPLATE = u'\nwindow.__resources__["%s"] = {meta: {mimetype: "%s"}, data: %s};\n' -CODE_RESOURCE_TEMPLATE = u''' -window.__resources__['%s'] = {meta: {mimetype: "%s"}, data: function(exports, require, module, __filename, __dirname) { -%s -}}; -''' - -mimetypes.add_type('application/xml', '.tmx') -mimetypes.add_type('application/xml', '.tsx') -mimetypes.add_type('application/xml', '.plist') - -class Compiler: - config = None - output = 'cocos2d.js' - main_module = 'main' - header_code = u'' - footer_code = u'' - valid_extensions = None - - def __init__(self, config_file=None): - self.config = self.load_config(config_file) - - module_js = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'module.js') - self.footer_code = open(module_js).read() - self.header_code = u''' -if (!window.__resources__) { window.__resources__ = {}; } -if (!window.__imageResource) { window.__imageResource = function(data) { var img = new Image(); img.src = data; return img; }; } -var __main_module_name__ = %s -''' % json.dumps(self.main_module) - - def load_config(self, config_file): - print "Loading config:", config_file - f = open(config_file, 'r') - config = json.loads(f.read()) - self.output = config['output'] - self.main_module = config['main_module'] or 'main' - self.valid_extensions = config['extensions'] - - return config - - def make(self): - code = self.header_code - for source, dest in self.config['paths'].items(): - code += self.make_path(source, root_path=dest, include_header=False, include_footer=False) - code += self.footer_code - return code - - - def make_path(self, source, strip_source=True, root_path='/', include_header=True, include_footer=False): - print "Building:", source - if not include_header: - code = '' - else: - code = self.header_code - - source = os.path.normpath(source) - - # If refrences to a single file we won't bother walking - if os.path.isfile(source): - f = source - if self.valid_extensions and os.path.splitext(f)[1][1:] not in self.valid_extensions: - print "Skipping:", f - return - - if strip_source: # Remove source path prefix - resource_name = '%s%s' % (root_path, f[len(source) +1:]) - else: - resource_name = '%s%s' % (root_path, f) - - code += self.read_file(f, resource_name) - - else: # If it's a directory we'll include everything in it - for root, dirs, files in os.walk(source): - for f in files: - if f[0] == '.': - continue - - path = os.path.join(root, f) - - if strip_source: # Remove source path prefix - resource_name = '%s%s' % (root_path, path[len(source) +1:]) - else: - resource_name = '%s%s' % (root_path, path) - - code += self.read_file(path, resource_name) - - - - if include_footer: - code += self.footer_code - - return code - - def read_file(self, filename, resource_name): - if self.valid_extensions and os.path.splitext(filename)[1][1:] not in self.valid_extensions: - print "Skipping:", filename - return '' - - resource_name = resource_name.replace('\\', '/') - print "Reading: '%s' --> '%s'" % (filename, resource_name) - - mimetype = mimetypes.guess_type(filename)[0] - - is_code = (mimetype in CODE_MIMETYPES) - is_text = (mimetype in TEXT_MIMETYPES) - is_image = (mimetype.split('/')[0] == 'image') - - data = StringIO() - - if is_code: - file_code = codecs.open(filename, 'r', encoding='utf-8').read() - file_code = self.parse_supers(file_code) - code = CODE_RESOURCE_TEMPLATE % (resource_name, mimetype, file_code) - elif is_text: - code = TEXT_RESOURCE_TEMPLATE % (resource_name, mimetype, json.dumps(open(filename, 'r').read())) - elif is_image: - base64.encode(open(filename, 'rb'), data) - code = IMAGE_RESOURCE_TEMPLATE % (resource_name, mimetype, mimetype, data.getvalue().replace('\n', '').replace('\r', '')) - else: # Binaries - base64.encode(open(filename, 'rb'), data) - code = BINARY_RESOURCE_TEMPLATE % (resource_name, mimetype, data.getvalue().replace('\n', '').replace('\r', '')) - - return code - - def parse_supers(self, code): - """ - Changes: - @super('foo', 'bar'); - @super() - @super - - Into: - arguments.callee.base.call(this, 'foo', 'bar'); - arguments.callee.base.call(this); - arguments.callee.base.apply(this, arguments); - """ - - def replace_super_apply(matches): - return '%sarguments.callee.base.apply(this, arguments);' % (matches.group('indent')) - - def replace_super(matches): - args = '' - if matches.group('args'): - args = ', %s' % matches.group('args') - - return '%sarguments.callee.base.call(this%s);' % (matches.group('indent'), args) - - super_re = re.compile('''(?P[ \t]*)@super\((?P.*)\)\s*;''') - code = super_re.sub(replace_super, code) - - super_re = re.compile('''(?P[ \t]*)@super\s*;''') - code = super_re.sub(replace_super_apply, code) - - return code - - -def main(): - parser = OptionParser(usage="Usage: cocos make [options]") - parser.add_option("-c", "--config", dest="config", - help="configuration file. Default is make.js", metavar="CONFIG") - - parser.add_option("-f", "--file", dest="output", - help="write code to FILE. Overrides config file", metavar="FILE") - - parser.add_option("-s", "--source", dest="input", - help="compile everything in SRC. Config is ignored if specified", metavar="SRC") - - (options, args) = parser.parse_args() - - compiler = Compiler(options.config or 'make.js') - - if options.input: - code = compiler.make_path(options.input) - else: - code = compiler.make() - - output = options.output or compiler.output - if output: - print "Writing output to:", output - o = codecs.open(output, 'w', encoding='utf-8') - o.write(code) - o.close() - else: - print code - -if __name__ == "__main__": - main() - diff --git a/scripts/new.py b/scripts/new.py deleted file mode 100755 index d758143..0000000 --- a/scripts/new.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python - -from optparse import OptionParser -import subprocess -import sys, re, os, base64, mimetypes, codecs, shutil - -INDEX_TEMPLATE = ''' - - - - - - {project_name} - - - -

{project_name}

-
- - -''' - -MAKE_JS_TEMPLATE = ''' -{{ - "output": "public/{script_name}", - "extensions": ["js", "gif", "jpeg", "jpg", "png", "tmx", "tsx", "plist"], - "main_module": "main", - - "paths": {{ - "cocos2d/src" : "/", - "src" : "/" - }} -}} -''' - -MAIN_JS_TEMPLATE = ''' -// Import the cocos2d module -var cocos = require('cocos2d'), -// Import the geometry module - geo = require('geometry'); - -// Create a new layer -var {class_name} = cocos.nodes.Layer.extend({{ - init: function() {{ - // You must always call the super class version of init - @super; - - // Get size of canvas - var s = cocos.Director.get('sharedDirector').get('winSize'); - - // Create label - var label = cocos.nodes.Label.create({{string: '{project_name}', fontName: 'Arial', fontSize: 76}}); - - // Add label to layer - this.addChild({{child: label, z:1}}); - - // Position the label in the centre of the view - label.set('position', geo.ccp(s.width / 2, s.height / 2)); - }} -}}); - -// Initialise everything - -// Get director -var director = cocos.Director.get('sharedDirector'); - -// Attach director to our
element -director.attachInView(document.getElementById('cocos2d-app')); - -// Create a scene -var scene = cocos.nodes.Scene.create(); - -// Add our layer to the scene -scene.addChild({{child: {class_name}.create()}}); - -// Run the scene -director.runWithScene(scene); -''' - - -def main(): - def removeNonAscii(s): - return "".join(i for i in s if ord(i) < 128) - - parser = OptionParser(usage="Usage: cocos new APP_PATH") - parser.add_option("-g", "--no-git", action="https://github.com/store_true", dest="nogit") - - (options, args) = parser.parse_args() - - if not str(args[0]).strip(): - print "Usage: cocos new APP_PATH" - return 1 - - - use_git = not options.nogit - project_path = os.path.abspath(args[0]) - project_name = os.path.basename(project_path) - script_name = removeNonAscii(project_name.lower().replace(' ', '_')) +'.js' - class_name = re.sub('(?:^| )(.)', lambda m: m.group(1).upper(), removeNonAscii(project_name.lower())) - - paths = ( - 'src', - 'src/resources', - 'public', - ) - - # Create initial folders - print "Creating cocos2d-javascript project in: %s" % project_path - for p in paths: - full_path = os.path.join(project_path, p) - if not os.path.exists(full_path): - print "Creating new directory : %s" % full_path - os.makedirs(full_path) - - subs = {'project_name': project_name, 'script_name': script_name, 'class_name': class_name} - - # Write out public/index.html - index = open(os.path.join(project_path, 'public/index.html'), 'w') - index.write(INDEX_TEMPLATE.format(**subs)) - index.close() - - # Write out make.js - make_js = open(os.path.join(project_path, 'make.js'), 'w') - make_js.write(MAKE_JS_TEMPLATE.format(**subs)) - make_js.close() - - # Write out src/main.js - main_js = open(os.path.join(project_path, 'src/main.js'), 'w') - main_js.write(MAIN_JS_TEMPLATE.format(**subs)) - main_js.close() - - - # Create cocos2d code - if use_git: - print "Creating cocos2d git submodule" - os.chdir(project_path) - subprocess.call(['git', 'init']) - subprocess.call(['git', 'submodule', 'add', 'git://github.com/ryanwilliams/cocos2d-javascript.git', 'cocos2d']) - else: - print "Copying cocos2d" - cocos_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) - shutil.copytree(cocos_path, os.path.join(project_path, 'cocos2d')) - os.chdir(project_path) - - shutil.copy2('cocos2d/cocos', './cocos') - shutil.copy2('cocos2d/cocos.bat', './cocos.bat') - - - - -if __name__ == "__main__": - main() diff --git a/scripts/server.py b/scripts/server.py deleted file mode 100755 index 522e6b9..0000000 --- a/scripts/server.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python - -from optparse import OptionParser -import SocketServer -import SimpleHTTPServer -import urllib -import threading -from make import Compiler -import os, sys, re, time, socket - -CODE_URL = None -CONFIG_FILE = 'make.js' - -class Cocos2D(SimpleHTTPServer.SimpleHTTPRequestHandler): - - def __init__(self, *args): - global CODE_URL, CONFIG_FILE - self.compiler = Compiler(CONFIG_FILE) - if not CODE_URL: - CODE_URL = re.sub('^/?public', '', self.compiler.output) - print "Serving as:", CODE_URL - SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args) - - - def do_GET(self): - self.path = self.path.split('?')[0] # Strip off params - if self.path == '/': - self.path = '/public/index.html' - return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) - else: - if CODE_URL == self.path: - print "Building code" - code = self.compiler.make() - - self.send_response(200) - self.send_header('Content-Type', 'text/javascript') - self.end_headers() - self.wfile.write(code.encode('utf-8')) - - else: - self.path = '/public' + os.path.normpath(self.path) - return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) - -def main(): - global CODE_URL, CONFIG_FILE - parser = OptionParser(usage="Usage: cocos server [options]") - parser.add_option("-c", "--config", dest="config", - help="configuration file. Default is make.js", metavar="CONFIG") - - parser.add_option("-u", "--url", dest="url", - help="the URL to serve the JS as. Default is output defined in the config file", metavar="URL") - - parser.add_option("-l", "--host", dest="host", - help="the host/ip to listen on. Default is 127.0.0.1", metavar="HOST") - - parser.add_option("-p", "--port", dest="port", - help="the port to listen on. Default is 4000", metavar="PORT") - - (options, args) = parser.parse_args() - - if options.url and options.url[0] != '/': - options.url = '/' + options.url - - host = options.host or 'localhost' - port = int(options.port) if options.port else 4000 - - if options.url: - CODE_URL = options.url - if options.config: - CONFIG_FILE = options.config - - httpd = SocketServer.TCPServer((host, port), Cocos2D) - httpd.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - httpd_thread = threading.Thread(target=httpd.serve_forever) - httpd_thread.setDaemon(True) - httpd_thread.start() - print "Listening at http://%s:%d/" % (host, port) - - - running = True - while running: - try: - time.sleep(3600) - except (KeyboardInterrupt, SystemExit): - running = False - print "Shutting down" - httpd.shutdown() - httpd.server_close() - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) - diff --git a/src/event.js b/src/events.js similarity index 73% rename from src/event.js rename to src/events.js index 357c040..ea7a6dd 100644 --- a/src/event.js +++ b/src/events.js @@ -1,12 +1,11 @@ /*global module exports require*/ /*jslint white: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true*/ - /** * @namespace * Support for listening for and triggering events */ -var event = {}; +var events = {}; /** * @private @@ -39,7 +38,7 @@ var eventID = 0; /** * @class * Represents an event being listened to. You should not create instances of - * this directly, it is instead returned by event.addListener + * this directly, it is instead returned by events.addListener * * @extends Object * @@ -47,7 +46,7 @@ var eventID = 0; * @param {String} eventName Name of the event to listen for * @param {Function} handler Callback to fire when the event triggers */ -event.EventListener = function (source, eventName, handler) { +events.EventListener = function (source, eventName, handler) { /** * Object to listen to for an event * @type Object @@ -79,13 +78,21 @@ event.EventListener = function (source, eventName, handler) { * Register an event listener * * @param {Object} source Object to listen to for an event - * @param {String} eventName Name of the event to listen for + * @param {String|Stringp[} eventName Name or Array of names of the event(s) to listen for * @param {Function} handler Callback to fire when the event triggers * - * @returns {event.EventListener} The event listener. Pass to removeListener to destroy it. + * @returns {events.EventListener|events.EventListener[]} The event listener(s). Pass to removeListener to destroy it. */ -event.addListener = function (source, eventName, handler) { - return new event.EventListener(source, eventName, handler); +events.addListener = function (source, eventName, handler) { + if (eventName instanceof Array) { + var listeners = []; + for (var i = 0, len = eventName.length; i < len; i++) { + listeners.push(new events.EventListener(source, eventName[i], handler)); + } + return listeners; + } else { + return new events.EventListener(source, eventName, handler); + } }; /** @@ -94,7 +101,7 @@ event.addListener = function (source, eventName, handler) { * @param {Object} source Object to trigger the event on * @param {String} eventName Name of the event to trigger */ -event.trigger = function (source, eventName) { +events.trigger = function (source, eventName) { var listeners = getListeners(source, eventName), args = Array.prototype.slice.call(arguments, 2), eventID, @@ -113,9 +120,9 @@ event.trigger = function (source, eventName) { /** * Remove a previously registered event listener * - * @param {event.EventListener} listener EventListener to remove, as returned by event.addListener + * @param {events.EventListener} listener EventListener to remove, as returned by events.addListener */ -event.removeListener = function (listener) { +events.removeListener = function (listener) { delete getListeners(listener.source, listener.eventName)[listener.eventID]; }; @@ -125,7 +132,7 @@ event.removeListener = function (listener) { * @param {Object} source Object to remove listeners from * @param {String} eventName Name of event to remove listeners from */ -event.clearListeners = function (source, eventName) { +events.clearListeners = function (source, eventName) { var listeners = getListeners(source, eventName), eventID; @@ -134,7 +141,7 @@ event.clearListeners = function (source, eventName) { if (listeners.hasOwnProperty(eventID)) { var l = listeners[eventID]; if (l) { - event.removeListener(l); + events.removeListener(l); } } } @@ -145,18 +152,18 @@ event.clearListeners = function (source, eventName) { * * @param {Object} source Object to remove listeners from */ -event.clearInstanceListeners = function (source, eventName) { +events.clearInstanceListeners = function (source) { var listeners = getListeners(source), eventID; - for (eventName in listeners) { + for (var eventName in listeners) { if (listeners.hasOwnProperty(eventName)) { var el = listeners[eventName]; for (eventID in el) { if (el.hasOwnProperty(eventID)) { var l = el[eventID]; if (l) { - event.removeListener(l); + events.removeListener(l); } } } @@ -164,4 +171,4 @@ event.clearInstanceListeners = function (source, eventName) { } }; -module.exports = event; +module.exports = events; diff --git a/src/global.js b/src/global.js index 6ca02ef..049ef0e 100644 --- a/src/global.js +++ b/src/global.js @@ -1,5 +1,9 @@ +/*globals module exports resource require*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - event = require('event'); + events = require('events'); /** @@ -67,20 +71,35 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ * access the property directly. This will ensure all bindings, setters and * getters work correctly. * - * @param {String} key Name of property to get + * @param {String} key Name of property to get or dot (.) separated path to a property * @returns {*} Value of the property */ get: function (key) { - var accessor = getAccessors(this)[key]; + var next = false + if (~key.indexOf('.')) { + var tokens = key.split('.'); + key = tokens.shift(); + next = tokens.join('.'); + } + + + var accessor = getAccessors(this)[key], + val; if (accessor) { - return accessor.target.get(accessor.key); + val = accessor.target.get(accessor.key); } else { // Call getting function if (this['get_' + key]) { - return this['get_' + key](); + val = this['get_' + key](); + } else { + val = this[key]; } + } - return this[key]; + if (next) { + return val.get(next); + } else { + return val; } }, @@ -96,9 +115,14 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ set: function (key, value) { var accessor = getAccessors(this)[key], oldVal = this.get(key); + + + this.triggerBeforeChanged(key, oldVal); + if (accessor) { accessor.target.set(accessor.key, value); } else { + if (this['set_' + key]) { this['set_' + key](value); } else { @@ -146,8 +170,15 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ /** * @private */ - triggerChanged: function(key, oldVal) { - event.trigger(this, key.toLowerCase() + '_changed', oldVal); + triggerBeforeChanged: function (key, oldVal) { + events.trigger(this, key.toLowerCase() + '_before_changed', oldVal); + }, + + /** + * @private + */ + triggerChanged: function (key, oldVal) { + events.trigger(this, key.toLowerCase() + '_changed', oldVal); }, /** @@ -168,7 +199,7 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ var oldVal = this.get(key); // When bound property changes, trigger a 'changed' event on this one too - getBindings(this)[key] = event.addListener(target, targetKey.toLowerCase() + '_changed', function (oldVal) { + getBindings(this)[key] = events.addListener(target, targetKey.toLowerCase() + '_changed', function (oldVal) { self.triggerChanged(key, oldVal); }); @@ -187,7 +218,7 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ } delete getBindings(this)[key]; - event.removeListener(binding); + events.removeListener(binding); // Grab current value from bound property var val = this.get(key); delete getAccessors(this)[key]; @@ -211,8 +242,9 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ /** * Unique ID for this object * @getter id + * @type Integer */ - get_id: function() { + get_id: function () { if (!this._id) { this._id = ++objectID; } @@ -226,7 +258,7 @@ BObject.prototype = util.extend(BObject.prototype, /** @lends BObject# */{ * Create a new instance of this object * @returns {BObject} New instance of this object */ -BObject.create = function() { +BObject.create = function () { var ret = new this(); ret.init.apply(ret, arguments); return ret; @@ -239,28 +271,26 @@ BObject.create = function() { BObject.extend = function() { var newObj = function() {}, args = [], - i; + i, + x; // Copy 'class' methods for (x in this) { - // Don't copy built-ins - if (!this.hasOwnProperty(x)) { - continue; + if (this.hasOwnProperty(x)) { + newObj[x] = this[x]; } - - newObj[x] = this[x]; } // Add given properties to the prototype - newObj.prototype = util.beget(this.prototype) + newObj.prototype = util.beget(this.prototype); args.push(newObj.prototype); for (i = 0; i b.x ? this.x : b.x; + this.y = this.y > b.y ? this.y : b.y +}; +b2Vec2.prototype.Abs = function() { + if(this.x < 0) { + this.x = -this.x + } + if(this.y < 0) { + this.y = -this.y + } +}; +b2Vec2.prototype.Length = function() { + return Math.sqrt(this.x * this.x + this.y * this.y) +}; +b2Vec2.prototype.LengthSquared = function() { + return this.x * this.x + this.y * this.y +}; +b2Vec2.prototype.Normalize = function() { + var length = Math.sqrt(this.x * this.x + this.y * this.y); + if(length < Number.MIN_VALUE) { + return 0 + } + var invLength = 1 / length; + this.x *= invLength; + this.y *= invLength; + return length +}; +b2Vec2.prototype.IsValid = function() { + return b2Math.IsValid(this.x) && b2Math.IsValid(this.y) +}; +b2Vec2.prototype.x = 0; +b2Vec2.prototype.y = 0;var b2Vec3 = function(x, y, z) { + if(arguments.length == 3) { + this.x = x; + this.y = y; + this.z = z + } +}; +b2Vec3.prototype.SetZero = function() { + this.x = this.y = this.z = 0 +}; +b2Vec3.prototype.Set = function(x, y, z) { + this.x = x; + this.y = y; + this.z = z +}; +b2Vec3.prototype.SetV = function(v) { + this.x = v.x; + this.y = v.y; + this.z = v.z +}; +b2Vec3.prototype.GetNegative = function() { + return new b2Vec3(-this.x, -this.y, -this.z) +}; +b2Vec3.prototype.NegativeSelf = function() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z +}; +b2Vec3.prototype.Copy = function() { + return new b2Vec3(this.x, this.y, this.z) +}; +b2Vec3.prototype.Add = function(v) { + this.x += v.x; + this.y += v.y; + this.z += v.z +}; +b2Vec3.prototype.Subtract = function(v) { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z +}; +b2Vec3.prototype.Multiply = function(a) { + this.x *= a; + this.y *= a; + this.z *= a +}; +b2Vec3.prototype.x = 0; +b2Vec3.prototype.y = 0; +b2Vec3.prototype.z = 0;var b2DistanceProxy = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DistanceProxy.prototype.__constructor = function() { +}; +b2DistanceProxy.prototype.__varz = function() { +}; +b2DistanceProxy.prototype.Set = function(shape) { + switch(shape.GetType()) { + case b2Shape.e_circleShape: + var circle = shape; + this.m_vertices = new Array(1); + this.m_vertices[0] = circle.m_p; + this.m_count = 1; + this.m_radius = circle.m_radius; + break; + case b2Shape.e_polygonShape: + var polygon = shape; + this.m_vertices = polygon.m_vertices; + this.m_count = polygon.m_vertexCount; + this.m_radius = polygon.m_radius; + break; + default: + b2Settings.b2Assert(false) + } +}; +b2DistanceProxy.prototype.GetSupport = function(d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for(var i = 1;i < this.m_count;++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if(value > bestValue) { + bestIndex = i; + bestValue = value + } + } + return bestIndex +}; +b2DistanceProxy.prototype.GetSupportVertex = function(d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for(var i = 1;i < this.m_count;++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if(value > bestValue) { + bestIndex = i; + bestValue = value + } + } + return this.m_vertices[bestIndex] +}; +b2DistanceProxy.prototype.GetVertexCount = function() { + return this.m_count +}; +b2DistanceProxy.prototype.GetVertex = function(index) { + b2Settings.b2Assert(0 <= index && index < this.m_count); + return this.m_vertices[index] +}; +b2DistanceProxy.prototype.m_vertices = null; +b2DistanceProxy.prototype.m_count = 0; +b2DistanceProxy.prototype.m_radius = null;var b2ContactFactory = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactFactory.prototype.__constructor = function() { +}; +b2ContactFactory.prototype.__varz = function() { + this.InitializeRegisters() +}; +b2ContactFactory.prototype.AddType = function(createFcn, destroyFcn, type1, type2) { + this.m_registers[type1][type2].createFcn = createFcn; + this.m_registers[type1][type2].destroyFcn = destroyFcn; + this.m_registers[type1][type2].primary = true; + if(type1 != type2) { + this.m_registers[type2][type1].createFcn = createFcn; + this.m_registers[type2][type1].destroyFcn = destroyFcn; + this.m_registers[type2][type1].primary = false + } +}; +b2ContactFactory.prototype.InitializeRegisters = function() { + this.m_registers = new Array(b2Shape.e_shapeTypeCount); + for(var i = 0;i < b2Shape.e_shapeTypeCount;i++) { + this.m_registers[i] = new Array(b2Shape.e_shapeTypeCount); + for(var j = 0;j < b2Shape.e_shapeTypeCount;j++) { + this.m_registers[i][j] = new b2ContactRegister + } + } + this.AddType(b2CircleContact.Create, b2CircleContact.Destroy, b2Shape.e_circleShape, b2Shape.e_circleShape); + this.AddType(b2PolyAndCircleContact.Create, b2PolyAndCircleContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_circleShape); + this.AddType(b2PolygonContact.Create, b2PolygonContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_polygonShape); + this.AddType(b2EdgeAndCircleContact.Create, b2EdgeAndCircleContact.Destroy, b2Shape.e_edgeShape, b2Shape.e_circleShape); + this.AddType(b2PolyAndEdgeContact.Create, b2PolyAndEdgeContact.Destroy, b2Shape.e_polygonShape, b2Shape.e_edgeShape) +}; +b2ContactFactory.prototype.Create = function(fixtureA, fixtureB) { + var type1 = fixtureA.GetType(); + var type2 = fixtureB.GetType(); + var reg = this.m_registers[type1][type2]; + var c; + if(reg.pool) { + c = reg.pool; + reg.pool = c.m_next; + reg.poolCount--; + c.Reset(fixtureA, fixtureB); + return c + } + var createFcn = reg.createFcn; + if(createFcn != null) { + if(reg.primary) { + c = createFcn(this.m_allocator); + c.Reset(fixtureA, fixtureB); + return c + }else { + c = createFcn(this.m_allocator); + c.Reset(fixtureB, fixtureA); + return c + } + }else { + return null + } +}; +b2ContactFactory.prototype.Destroy = function(contact) { + if(contact.m_manifold.m_pointCount > 0) { + contact.m_fixtureA.m_body.SetAwake(true); + contact.m_fixtureB.m_body.SetAwake(true) + } + var type1 = contact.m_fixtureA.GetType(); + var type2 = contact.m_fixtureB.GetType(); + var reg = this.m_registers[type1][type2]; + if(true) { + reg.poolCount++; + contact.m_next = reg.pool; + reg.pool = contact + } + var destroyFcn = reg.destroyFcn; + destroyFcn(contact, this.m_allocator) +}; +b2ContactFactory.prototype.m_registers = null; +b2ContactFactory.prototype.m_allocator = null;var b2ConstantAccelController = function() { + b2Controller.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2ConstantAccelController.prototype, b2Controller.prototype); +b2ConstantAccelController.prototype._super = b2Controller.prototype; +b2ConstantAccelController.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2ConstantAccelController.prototype.__varz = function() { + this.A = new b2Vec2(0, 0) +}; +b2ConstantAccelController.prototype.Step = function(step) { + var smallA = new b2Vec2(this.A.x * step.dt, this.A.y * step.dt); + for(var i = m_bodyList;i;i = i.nextBody) { + var body = i.body; + if(!body.IsAwake()) { + continue + } + body.SetLinearVelocity(new b2Vec2(body.GetLinearVelocity().x + smallA.x, body.GetLinearVelocity().y + smallA.y)) + } +}; +b2ConstantAccelController.prototype.A = new b2Vec2(0, 0);var b2SeparationFunction = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2SeparationFunction.prototype.__constructor = function() { +}; +b2SeparationFunction.prototype.__varz = function() { + this.m_localPoint = new b2Vec2; + this.m_axis = new b2Vec2 +}; +b2SeparationFunction.e_points = 1; +b2SeparationFunction.e_faceA = 2; +b2SeparationFunction.e_faceB = 4; +b2SeparationFunction.prototype.Initialize = function(cache, proxyA, transformA, proxyB, transformB) { + this.m_proxyA = proxyA; + this.m_proxyB = proxyB; + var count = cache.count; + b2Settings.b2Assert(0 < count && count < 3); + var localPointA; + var localPointA1; + var localPointA2; + var localPointB; + var localPointB1; + var localPointB2; + var pointAX; + var pointAY; + var pointBX; + var pointBY; + var normalX; + var normalY; + var tMat; + var tVec; + var s; + var sgn; + if(count == 1) { + this.m_type = b2SeparationFunction.e_points; + localPointA = this.m_proxyA.GetVertex(cache.indexA[0]); + localPointB = this.m_proxyB.GetVertex(cache.indexB[0]); + tVec = localPointA; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointB; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_axis.x = pointBX - pointAX; + this.m_axis.y = pointBY - pointAY; + this.m_axis.Normalize() + }else { + if(cache.indexB[0] == cache.indexB[1]) { + this.m_type = b2SeparationFunction.e_faceA; + localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]); + localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]); + localPointB = this.m_proxyB.GetVertex(cache.indexB[0]); + this.m_localPoint.x = 0.5 * (localPointA1.x + localPointA2.x); + this.m_localPoint.y = 0.5 * (localPointA1.y + localPointA2.y); + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointA2, localPointA1), 1); + this.m_axis.Normalize(); + tVec = this.m_axis; + tMat = transformA.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointB; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + s = (pointBX - pointAX) * normalX + (pointBY - pointAY) * normalY; + if(s < 0) { + this.m_axis.NegativeSelf() + } + }else { + if(cache.indexA[0] == cache.indexA[0]) { + this.m_type = b2SeparationFunction.e_faceB; + localPointB1 = this.m_proxyB.GetVertex(cache.indexB[0]); + localPointB2 = this.m_proxyB.GetVertex(cache.indexB[1]); + localPointA = this.m_proxyA.GetVertex(cache.indexA[0]); + this.m_localPoint.x = 0.5 * (localPointB1.x + localPointB2.x); + this.m_localPoint.y = 0.5 * (localPointB1.y + localPointB2.y); + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointB2, localPointB1), 1); + this.m_axis.Normalize(); + tVec = this.m_axis; + tMat = transformB.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointA; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + s = (pointAX - pointBX) * normalX + (pointAY - pointBY) * normalY; + if(s < 0) { + this.m_axis.NegativeSelf() + } + }else { + localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]); + localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]); + localPointB1 = this.m_proxyB.GetVertex(cache.indexB[0]); + localPointB2 = this.m_proxyB.GetVertex(cache.indexB[1]); + var pA = b2Math.MulX(transformA, localPointA); + var dA = b2Math.MulMV(transformA.R, b2Math.SubtractVV(localPointA2, localPointA1)); + var pB = b2Math.MulX(transformB, localPointB); + var dB = b2Math.MulMV(transformB.R, b2Math.SubtractVV(localPointB2, localPointB1)); + var a = dA.x * dA.x + dA.y * dA.y; + var e = dB.x * dB.x + dB.y * dB.y; + var r = b2Math.SubtractVV(dB, dA); + var c = dA.x * r.x + dA.y * r.y; + var f = dB.x * r.x + dB.y * r.y; + var b = dA.x * dB.x + dA.y * dB.y; + var denom = a * e - b * b; + s = 0; + if(denom != 0) { + s = b2Math.Clamp((b * f - c * e) / denom, 0, 1) + } + var t = (b * s + f) / e; + if(t < 0) { + t = 0; + s = b2Math.Clamp((b - c) / a, 0, 1) + } + localPointA = new b2Vec2; + localPointA.x = localPointA1.x + s * (localPointA2.x - localPointA1.x); + localPointA.y = localPointA1.y + s * (localPointA2.y - localPointA1.y); + localPointB = new b2Vec2; + localPointB.x = localPointB1.x + s * (localPointB2.x - localPointB1.x); + localPointB.y = localPointB1.y + s * (localPointB2.y - localPointB1.y); + if(s == 0 || s == 1) { + this.m_type = b2SeparationFunction.e_faceB; + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointB2, localPointB1), 1); + this.m_axis.Normalize(); + this.m_localPoint = localPointB; + tVec = this.m_axis; + tMat = transformB.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointA; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + sgn = (pointAX - pointBX) * normalX + (pointAY - pointBY) * normalY; + if(s < 0) { + this.m_axis.NegativeSelf() + } + }else { + this.m_type = b2SeparationFunction.e_faceA; + this.m_axis = b2Math.CrossVF(b2Math.SubtractVV(localPointA2, localPointA1), 1); + this.m_localPoint = localPointA; + tVec = this.m_axis; + tMat = transformA.R; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tVec = this.m_localPoint; + tMat = transformA.R; + pointAX = transformA.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointAY = transformA.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = localPointB; + tMat = transformB.R; + pointBX = transformB.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + pointBY = transformB.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + sgn = (pointBX - pointAX) * normalX + (pointBY - pointAY) * normalY; + if(s < 0) { + this.m_axis.NegativeSelf() + } + } + } + } + } +}; +b2SeparationFunction.prototype.Evaluate = function(transformA, transformB) { + var axisA; + var axisB; + var localPointA; + var localPointB; + var pointA; + var pointB; + var seperation; + var normal; + switch(this.m_type) { + case b2SeparationFunction.e_points: + axisA = b2Math.MulTMV(transformA.R, this.m_axis); + axisB = b2Math.MulTMV(transformB.R, this.m_axis.GetNegative()); + localPointA = this.m_proxyA.GetSupportVertex(axisA); + localPointB = this.m_proxyB.GetSupportVertex(axisB); + pointA = b2Math.MulX(transformA, localPointA); + pointB = b2Math.MulX(transformB, localPointB); + seperation = (pointB.x - pointA.x) * this.m_axis.x + (pointB.y - pointA.y) * this.m_axis.y; + return seperation; + case b2SeparationFunction.e_faceA: + normal = b2Math.MulMV(transformA.R, this.m_axis); + pointA = b2Math.MulX(transformA, this.m_localPoint); + axisB = b2Math.MulTMV(transformB.R, normal.GetNegative()); + localPointB = this.m_proxyB.GetSupportVertex(axisB); + pointB = b2Math.MulX(transformB, localPointB); + seperation = (pointB.x - pointA.x) * normal.x + (pointB.y - pointA.y) * normal.y; + return seperation; + case b2SeparationFunction.e_faceB: + normal = b2Math.MulMV(transformB.R, this.m_axis); + pointB = b2Math.MulX(transformB, this.m_localPoint); + axisA = b2Math.MulTMV(transformA.R, normal.GetNegative()); + localPointA = this.m_proxyA.GetSupportVertex(axisA); + pointA = b2Math.MulX(transformA, localPointA); + seperation = (pointA.x - pointB.x) * normal.x + (pointA.y - pointB.y) * normal.y; + return seperation; + default: + b2Settings.b2Assert(false); + return 0 + } +}; +b2SeparationFunction.prototype.m_proxyA = null; +b2SeparationFunction.prototype.m_proxyB = null; +b2SeparationFunction.prototype.m_type = 0; +b2SeparationFunction.prototype.m_localPoint = new b2Vec2; +b2SeparationFunction.prototype.m_axis = new b2Vec2;var b2DynamicTreePair = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DynamicTreePair.prototype.__constructor = function() { +}; +b2DynamicTreePair.prototype.__varz = function() { +}; +b2DynamicTreePair.prototype.proxyA = null; +b2DynamicTreePair.prototype.proxyB = null;var b2ContactConstraintPoint = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactConstraintPoint.prototype.__constructor = function() { +}; +b2ContactConstraintPoint.prototype.__varz = function() { + this.localPoint = new b2Vec2; + this.rA = new b2Vec2; + this.rB = new b2Vec2 +}; +b2ContactConstraintPoint.prototype.localPoint = new b2Vec2; +b2ContactConstraintPoint.prototype.rA = new b2Vec2; +b2ContactConstraintPoint.prototype.rB = new b2Vec2; +b2ContactConstraintPoint.prototype.normalImpulse = null; +b2ContactConstraintPoint.prototype.tangentImpulse = null; +b2ContactConstraintPoint.prototype.normalMass = null; +b2ContactConstraintPoint.prototype.tangentMass = null; +b2ContactConstraintPoint.prototype.equalizedMass = null; +b2ContactConstraintPoint.prototype.velocityBias = null;var b2ControllerEdge = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ControllerEdge.prototype.__constructor = function() { +}; +b2ControllerEdge.prototype.__varz = function() { +}; +b2ControllerEdge.prototype.controller = null; +b2ControllerEdge.prototype.body = null; +b2ControllerEdge.prototype.prevBody = null; +b2ControllerEdge.prototype.nextBody = null; +b2ControllerEdge.prototype.prevController = null; +b2ControllerEdge.prototype.nextController = null;var b2DistanceInput = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DistanceInput.prototype.__constructor = function() { +}; +b2DistanceInput.prototype.__varz = function() { +}; +b2DistanceInput.prototype.proxyA = null; +b2DistanceInput.prototype.proxyB = null; +b2DistanceInput.prototype.transformA = null; +b2DistanceInput.prototype.transformB = null; +b2DistanceInput.prototype.useRadii = null;var b2Settings = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Settings.prototype.__constructor = function() { +}; +b2Settings.prototype.__varz = function() { +}; +b2Settings.b2MixFriction = function(friction1, friction2) { + return Math.sqrt(friction1 * friction2) +}; +b2Settings.b2MixRestitution = function(restitution1, restitution2) { + return restitution1 > restitution2 ? restitution1 : restitution2 +}; +b2Settings.b2Assert = function(a) { + if(!a) { + throw"Assertion Failed"; + } +}; +b2Settings.VERSION = "2.1alpha"; +b2Settings.USHRT_MAX = 65535; +b2Settings.b2_pi = Math.PI; +b2Settings.b2_maxManifoldPoints = 2; +b2Settings.b2_aabbExtension = 0.1; +b2Settings.b2_aabbMultiplier = 2; +b2Settings.b2_polygonRadius = 2 * b2Settings.b2_linearSlop; +b2Settings.b2_linearSlop = 0.0050; +b2Settings.b2_angularSlop = 2 / 180 * b2Settings.b2_pi; +b2Settings.b2_toiSlop = 8 * b2Settings.b2_linearSlop; +b2Settings.b2_maxTOIContactsPerIsland = 32; +b2Settings.b2_maxTOIJointsPerIsland = 32; +b2Settings.b2_velocityThreshold = 1; +b2Settings.b2_maxLinearCorrection = 0.2; +b2Settings.b2_maxAngularCorrection = 8 / 180 * b2Settings.b2_pi; +b2Settings.b2_maxTranslation = 2; +b2Settings.b2_maxTranslationSquared = b2Settings.b2_maxTranslation * b2Settings.b2_maxTranslation; +b2Settings.b2_maxRotation = 0.5 * b2Settings.b2_pi; +b2Settings.b2_maxRotationSquared = b2Settings.b2_maxRotation * b2Settings.b2_maxRotation; +b2Settings.b2_contactBaumgarte = 0.2; +b2Settings.b2_timeToSleep = 0.5; +b2Settings.b2_linearSleepTolerance = 0.01; +b2Settings.b2_angularSleepTolerance = 2 / 180 * b2Settings.b2_pi;var b2Proxy = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Proxy.prototype.__constructor = function() { +}; +b2Proxy.prototype.__varz = function() { + this.lowerBounds = new Array(2); + this.upperBounds = new Array(2); + this.pairs = new Object +}; +b2Proxy.prototype.IsValid = function() { + return this.overlapCount != b2BroadPhase.b2_invalid +}; +b2Proxy.prototype.lowerBounds = new Array(2); +b2Proxy.prototype.upperBounds = new Array(2); +b2Proxy.prototype.overlapCount = 0; +b2Proxy.prototype.timeStamp = 0; +b2Proxy.prototype.pairs = new Object; +b2Proxy.prototype.next = null; +b2Proxy.prototype.userData = null;var b2Point = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Point.prototype.__constructor = function() { +}; +b2Point.prototype.__varz = function() { + this.p = new b2Vec2 +}; +b2Point.prototype.Support = function(xf, vX, vY) { + return this.p +}; +b2Point.prototype.GetFirstVertex = function(xf) { + return this.p +}; +b2Point.prototype.p = new b2Vec2;var b2WorldManifold = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2WorldManifold.prototype.__constructor = function() { + this.m_points = new Array(b2Settings.b2_maxManifoldPoints); + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;i++) { + this.m_points[i] = new b2Vec2 + } +}; +b2WorldManifold.prototype.__varz = function() { + this.m_normal = new b2Vec2 +}; +b2WorldManifold.prototype.Initialize = function(manifold, xfA, radiusA, xfB, radiusB) { + if(manifold.m_pointCount == 0) { + return + } + var i = 0; + var tVec; + var tMat; + var normalX; + var normalY; + var planePointX; + var planePointY; + var clipPointX; + var clipPointY; + switch(manifold.m_type) { + case b2Manifold.e_circles: + tMat = xfA.R; + tVec = manifold.m_localPoint; + var pointAX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + var pointAY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xfB.R; + tVec = manifold.m_points[0].m_localPoint; + var pointBX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + var pointBY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + var dX = pointBX - pointAX; + var dY = pointBY - pointAY; + var d2 = dX * dX + dY * dY; + if(d2 > Number.MIN_VALUE * Number.MIN_VALUE) { + var d = Math.sqrt(d2); + this.m_normal.x = dX / d; + this.m_normal.y = dY / d + }else { + this.m_normal.x = 1; + this.m_normal.y = 0 + } + var cAX = pointAX + radiusA * this.m_normal.x; + var cAY = pointAY + radiusA * this.m_normal.y; + var cBX = pointBX - radiusB * this.m_normal.x; + var cBY = pointBY - radiusB * this.m_normal.y; + this.m_points[0].x = 0.5 * (cAX + cBX); + this.m_points[0].y = 0.5 * (cAY + cBY); + break; + case b2Manifold.e_faceA: + tMat = xfA.R; + tVec = manifold.m_localPlaneNormal; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xfA.R; + tVec = manifold.m_localPoint; + planePointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + planePointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_normal.x = normalX; + this.m_normal.y = normalY; + for(i = 0;i < manifold.m_pointCount;i++) { + tMat = xfB.R; + tVec = manifold.m_points[i].m_localPoint; + clipPointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + clipPointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_points[i].x = clipPointX + 0.5 * (radiusA - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusB) * normalX; + this.m_points[i].y = clipPointY + 0.5 * (radiusA - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusB) * normalY + } + break; + case b2Manifold.e_faceB: + tMat = xfB.R; + tVec = manifold.m_localPlaneNormal; + normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xfB.R; + tVec = manifold.m_localPoint; + planePointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + planePointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_normal.x = -normalX; + this.m_normal.y = -normalY; + for(i = 0;i < manifold.m_pointCount;i++) { + tMat = xfA.R; + tVec = manifold.m_points[i].m_localPoint; + clipPointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + clipPointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_points[i].x = clipPointX + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA) * normalX; + this.m_points[i].y = clipPointY + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA) * normalY + } + break + } +}; +b2WorldManifold.prototype.m_normal = new b2Vec2; +b2WorldManifold.prototype.m_points = null;var b2RayCastOutput = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2RayCastOutput.prototype.__constructor = function() { +}; +b2RayCastOutput.prototype.__varz = function() { + this.normal = new b2Vec2 +}; +b2RayCastOutput.prototype.normal = new b2Vec2; +b2RayCastOutput.prototype.fraction = null;var b2ConstantForceController = function() { + b2Controller.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2ConstantForceController.prototype, b2Controller.prototype); +b2ConstantForceController.prototype._super = b2Controller.prototype; +b2ConstantForceController.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2ConstantForceController.prototype.__varz = function() { + this.F = new b2Vec2(0, 0) +}; +b2ConstantForceController.prototype.Step = function(step) { + for(var i = m_bodyList;i;i = i.nextBody) { + var body = i.body; + if(!body.IsAwake()) { + continue + } + body.ApplyForce(this.F, body.GetWorldCenter()) + } +}; +b2ConstantForceController.prototype.F = new b2Vec2(0, 0);var b2MassData = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2MassData.prototype.__constructor = function() { +}; +b2MassData.prototype.__varz = function() { + this.center = new b2Vec2(0, 0) +}; +b2MassData.prototype.mass = 0; +b2MassData.prototype.center = new b2Vec2(0, 0); +b2MassData.prototype.I = 0;var b2DynamicTree = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DynamicTree.prototype.__constructor = function() { + this.m_root = null; + this.m_freeList = null; + this.m_path = 0; + this.m_insertionCount = 0 +}; +b2DynamicTree.prototype.__varz = function() { +}; +b2DynamicTree.prototype.AllocateNode = function() { + if(this.m_freeList) { + var node = this.m_freeList; + this.m_freeList = node.parent; + node.parent = null; + node.child1 = null; + node.child2 = null; + return node + } + return new b2DynamicTreeNode +}; +b2DynamicTree.prototype.FreeNode = function(node) { + node.parent = this.m_freeList; + this.m_freeList = node +}; +b2DynamicTree.prototype.InsertLeaf = function(leaf) { + ++this.m_insertionCount; + if(this.m_root == null) { + this.m_root = leaf; + this.m_root.parent = null; + return + } + var center = leaf.aabb.GetCenter(); + var sibling = this.m_root; + if(sibling.IsLeaf() == false) { + do { + var child1 = sibling.child1; + var child2 = sibling.child2; + var norm1 = Math.abs((child1.aabb.lowerBound.x + child1.aabb.upperBound.x) / 2 - center.x) + Math.abs((child1.aabb.lowerBound.y + child1.aabb.upperBound.y) / 2 - center.y); + var norm2 = Math.abs((child2.aabb.lowerBound.x + child2.aabb.upperBound.x) / 2 - center.x) + Math.abs((child2.aabb.lowerBound.y + child2.aabb.upperBound.y) / 2 - center.y); + if(norm1 < norm2) { + sibling = child1 + }else { + sibling = child2 + } + }while(sibling.IsLeaf() == false) + } + var node1 = sibling.parent; + var node2 = this.AllocateNode(); + node2.parent = node1; + node2.userData = null; + node2.aabb.Combine(leaf.aabb, sibling.aabb); + if(node1) { + if(sibling.parent.child1 == sibling) { + node1.child1 = node2 + }else { + node1.child2 = node2 + } + node2.child1 = sibling; + node2.child2 = leaf; + sibling.parent = node2; + leaf.parent = node2; + do { + if(node1.aabb.Contains(node2.aabb)) { + break + } + node1.aabb.Combine(node1.child1.aabb, node1.child2.aabb); + node2 = node1; + node1 = node1.parent + }while(node1) + }else { + node2.child1 = sibling; + node2.child2 = leaf; + sibling.parent = node2; + leaf.parent = node2; + this.m_root = node2 + } +}; +b2DynamicTree.prototype.RemoveLeaf = function(leaf) { + if(leaf == this.m_root) { + this.m_root = null; + return + } + var node2 = leaf.parent; + var node1 = node2.parent; + var sibling; + if(node2.child1 == leaf) { + sibling = node2.child2 + }else { + sibling = node2.child1 + } + if(node1) { + if(node1.child1 == node2) { + node1.child1 = sibling + }else { + node1.child2 = sibling + } + sibling.parent = node1; + this.FreeNode(node2); + while(node1) { + var oldAABB = node1.aabb; + node1.aabb = b2AABB.Combine(node1.child1.aabb, node1.child2.aabb); + if(oldAABB.Contains(node1.aabb)) { + break + } + node1 = node1.parent + } + }else { + this.m_root = sibling; + sibling.parent = null; + this.FreeNode(node2) + } +}; +b2DynamicTree.prototype.CreateProxy = function(aabb, userData) { + var node = this.AllocateNode(); + var extendX = b2Settings.b2_aabbExtension; + var extendY = b2Settings.b2_aabbExtension; + node.aabb.lowerBound.x = aabb.lowerBound.x - extendX; + node.aabb.lowerBound.y = aabb.lowerBound.y - extendY; + node.aabb.upperBound.x = aabb.upperBound.x + extendX; + node.aabb.upperBound.y = aabb.upperBound.y + extendY; + node.userData = userData; + this.InsertLeaf(node); + return node +}; +b2DynamicTree.prototype.DestroyProxy = function(proxy) { + this.RemoveLeaf(proxy); + this.FreeNode(proxy) +}; +b2DynamicTree.prototype.MoveProxy = function(proxy, aabb, displacement) { + b2Settings.b2Assert(proxy.IsLeaf()); + if(proxy.aabb.Contains(aabb)) { + return false + } + this.RemoveLeaf(proxy); + var extendX = b2Settings.b2_aabbExtension + b2Settings.b2_aabbMultiplier * (displacement.x > 0 ? displacement.x : -displacement.x); + var extendY = b2Settings.b2_aabbExtension + b2Settings.b2_aabbMultiplier * (displacement.y > 0 ? displacement.y : -displacement.y); + proxy.aabb.lowerBound.x = aabb.lowerBound.x - extendX; + proxy.aabb.lowerBound.y = aabb.lowerBound.y - extendY; + proxy.aabb.upperBound.x = aabb.upperBound.x + extendX; + proxy.aabb.upperBound.y = aabb.upperBound.y + extendY; + this.InsertLeaf(proxy); + return true +}; +b2DynamicTree.prototype.Rebalance = function(iterations) { + if(this.m_root == null) { + return + } + for(var i = 0;i < iterations;i++) { + var node = this.m_root; + var bit = 0; + while(node.IsLeaf() == false) { + node = this.m_path >> bit & 1 ? node.child2 : node.child1; + bit = bit + 1 & 31 + } + ++this.m_path; + this.RemoveLeaf(node); + this.InsertLeaf(node) + } +}; +b2DynamicTree.prototype.GetFatAABB = function(proxy) { + return proxy.aabb +}; +b2DynamicTree.prototype.GetUserData = function(proxy) { + return proxy.userData +}; +b2DynamicTree.prototype.Query = function(callback, aabb) { + if(this.m_root == null) { + return + } + var stack = new Array; + var count = 0; + stack[count++] = this.m_root; + while(count > 0) { + var node = stack[--count]; + if(node.aabb.TestOverlap(aabb)) { + if(node.IsLeaf()) { + var proceed = callback(node); + if(!proceed) { + return + } + }else { + stack[count++] = node.child1; + stack[count++] = node.child2 + } + } + } +}; +b2DynamicTree.prototype.RayCast = function(callback, input) { + if(this.m_root == null) { + return + } + var p1 = input.p1; + var p2 = input.p2; + var r = b2Math.SubtractVV(p1, p2); + r.Normalize(); + var v = b2Math.CrossFV(1, r); + var abs_v = b2Math.AbsV(v); + var maxFraction = input.maxFraction; + var segmentAABB = new b2AABB; + var tX; + var tY; + tX = p1.x + maxFraction * (p2.x - p1.x); + tY = p1.y + maxFraction * (p2.y - p1.y); + segmentAABB.lowerBound.x = Math.min(p1.x, tX); + segmentAABB.lowerBound.y = Math.min(p1.y, tY); + segmentAABB.upperBound.x = Math.max(p1.x, tX); + segmentAABB.upperBound.y = Math.max(p1.y, tY); + var stack = new Array; + var count = 0; + stack[count++] = this.m_root; + while(count > 0) { + var node = stack[--count]; + if(node.aabb.TestOverlap(segmentAABB) == false) { + continue + } + var c = node.aabb.GetCenter(); + var h = node.aabb.GetExtents(); + var separation = Math.abs(v.x * (p1.x - c.x) + v.y * (p1.y - c.y)) - abs_v.x * h.x - abs_v.y * h.y; + if(separation > 0) { + continue + } + if(node.IsLeaf()) { + var subInput = new b2RayCastInput; + subInput.p1 = input.p1; + subInput.p2 = input.p2; + subInput.maxFraction = input.maxFraction; + maxFraction = callback(subInput, node); + if(maxFraction == 0) { + return + } + tX = p1.x + maxFraction * (p2.x - p1.x); + tY = p1.y + maxFraction * (p2.y - p1.y); + segmentAABB.lowerBound.x = Math.min(p1.x, tX); + segmentAABB.lowerBound.y = Math.min(p1.y, tY); + segmentAABB.upperBound.x = Math.max(p1.x, tX); + segmentAABB.upperBound.y = Math.max(p1.y, tY) + }else { + stack[count++] = node.child1; + stack[count++] = node.child2 + } + } +}; +b2DynamicTree.prototype.m_root = null; +b2DynamicTree.prototype.m_freeList = null; +b2DynamicTree.prototype.m_path = 0; +b2DynamicTree.prototype.m_insertionCount = 0;var b2JointEdge = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2JointEdge.prototype.__constructor = function() { +}; +b2JointEdge.prototype.__varz = function() { +}; +b2JointEdge.prototype.other = null; +b2JointEdge.prototype.joint = null; +b2JointEdge.prototype.prev = null; +b2JointEdge.prototype.next = null;var b2RayCastInput = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2RayCastInput.prototype.__constructor = function() { +}; +b2RayCastInput.prototype.__varz = function() { + this.p1 = new b2Vec2; + this.p2 = new b2Vec2 +}; +b2RayCastInput.prototype.p1 = new b2Vec2; +b2RayCastInput.prototype.p2 = new b2Vec2; +b2RayCastInput.prototype.maxFraction = null;var Features = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +Features.prototype.__constructor = function() { +}; +Features.prototype.__varz = function() { +}; +Features.prototype.__defineGetter__("referenceEdge", function() { + return this._referenceEdge +}); +Features.prototype.__defineSetter__("referenceEdge", function(value) { + this._referenceEdge = value; + this._m_id._key = this._m_id._key & 4294967040 | this._referenceEdge & 255 +}); +Features.prototype.__defineGetter__("incidentEdge", function() { + return this._incidentEdge +}); +Features.prototype.__defineSetter__("incidentEdge", function(value) { + this._incidentEdge = value; + this._m_id._key = this._m_id._key & 4294902015 | this._incidentEdge << 8 & 65280 +}); +Features.prototype.__defineGetter__("incidentVertex", function() { + return this._incidentVertex +}); +Features.prototype.__defineSetter__("incidentVertex", function(value) { + this._incidentVertex = value; + this._m_id._key = this._m_id._key & 4278255615 | this._incidentVertex << 16 & 16711680 +}); +Features.prototype.__defineGetter__("flip", function() { + return this._flip +}); +Features.prototype.__defineSetter__("flip", function(value) { + this._flip = value; + this._m_id._key = this._m_id._key & 16777215 | this._flip << 24 & 4278190080 +}); +Features.prototype._referenceEdge = 0; +Features.prototype._incidentEdge = 0; +Features.prototype._incidentVertex = 0; +Features.prototype._flip = 0; +Features.prototype._m_id = null;var b2FilterData = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2FilterData.prototype.__constructor = function() { +}; +b2FilterData.prototype.__varz = function() { + this.categoryBits = 1; + this.maskBits = 65535 +}; +b2FilterData.prototype.Copy = function() { + var copy = new b2FilterData; + copy.categoryBits = this.categoryBits; + copy.maskBits = this.maskBits; + copy.groupIndex = this.groupIndex; + return copy +}; +b2FilterData.prototype.categoryBits = 1; +b2FilterData.prototype.maskBits = 65535; +b2FilterData.prototype.groupIndex = 0;var b2AABB = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2AABB.prototype.__constructor = function() { +}; +b2AABB.prototype.__varz = function() { + this.lowerBound = new b2Vec2; + this.upperBound = new b2Vec2 +}; +b2AABB.Combine = function(aabb1, aabb2) { + var aabb = new b2AABB; + aabb.Combine(aabb1, aabb2); + return aabb +}; +b2AABB.prototype.IsValid = function() { + var dX = this.upperBound.x - this.lowerBound.x; + var dY = this.upperBound.y - this.lowerBound.y; + var valid = dX >= 0 && dY >= 0; + valid = valid && this.lowerBound.IsValid() && this.upperBound.IsValid(); + return valid +}; +b2AABB.prototype.GetCenter = function() { + return new b2Vec2((this.lowerBound.x + this.upperBound.x) / 2, (this.lowerBound.y + this.upperBound.y) / 2) +}; +b2AABB.prototype.GetExtents = function() { + return new b2Vec2((this.upperBound.x - this.lowerBound.x) / 2, (this.upperBound.y - this.lowerBound.y) / 2) +}; +b2AABB.prototype.Contains = function(aabb) { + var result = true && this.lowerBound.x <= aabb.lowerBound.x && this.lowerBound.y <= aabb.lowerBound.y && aabb.upperBound.x <= this.upperBound.x && aabb.upperBound.y <= this.upperBound.y; + return result +}; +b2AABB.prototype.RayCast = function(output, input) { + var tmin = -Number.MAX_VALUE; + var tmax = Number.MAX_VALUE; + var pX = input.p1.x; + var pY = input.p1.y; + var dX = input.p2.x - input.p1.x; + var dY = input.p2.y - input.p1.y; + var absDX = Math.abs(dX); + var absDY = Math.abs(dY); + var normal = output.normal; + var inv_d; + var t1; + var t2; + var t3; + var s; + if(absDX < Number.MIN_VALUE) { + if(pX < this.lowerBound.x || this.upperBound.x < pX) { + return false + } + }else { + inv_d = 1 / dX; + t1 = (this.lowerBound.x - pX) * inv_d; + t2 = (this.upperBound.x - pX) * inv_d; + s = -1; + if(t1 > t2) { + t3 = t1; + t1 = t2; + t2 = t3; + s = 1 + } + if(t1 > tmin) { + normal.x = s; + normal.y = 0; + tmin = t1 + } + tmax = Math.min(tmax, t2); + if(tmin > tmax) { + return false + } + } + if(absDY < Number.MIN_VALUE) { + if(pY < this.lowerBound.y || this.upperBound.y < pY) { + return false + } + }else { + inv_d = 1 / dY; + t1 = (this.lowerBound.y - pY) * inv_d; + t2 = (this.upperBound.y - pY) * inv_d; + s = -1; + if(t1 > t2) { + t3 = t1; + t1 = t2; + t2 = t3; + s = 1 + } + if(t1 > tmin) { + normal.y = s; + normal.x = 0; + tmin = t1 + } + tmax = Math.min(tmax, t2); + if(tmin > tmax) { + return false + } + } + output.fraction = tmin; + return true +}; +b2AABB.prototype.TestOverlap = function(other) { + var d1X = other.lowerBound.x - this.upperBound.x; + var d1Y = other.lowerBound.y - this.upperBound.y; + var d2X = this.lowerBound.x - other.upperBound.x; + var d2Y = this.lowerBound.y - other.upperBound.y; + if(d1X > 0 || d1Y > 0) { + return false + } + if(d2X > 0 || d2Y > 0) { + return false + } + return true +}; +b2AABB.prototype.Combine = function(aabb1, aabb2) { + this.lowerBound.x = Math.min(aabb1.lowerBound.x, aabb2.lowerBound.x); + this.lowerBound.y = Math.min(aabb1.lowerBound.y, aabb2.lowerBound.y); + this.upperBound.x = Math.max(aabb1.upperBound.x, aabb2.upperBound.x); + this.upperBound.y = Math.max(aabb1.upperBound.y, aabb2.upperBound.y) +}; +b2AABB.prototype.lowerBound = new b2Vec2; +b2AABB.prototype.upperBound = new b2Vec2;var b2Jacobian = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Jacobian.prototype.__constructor = function() { +}; +b2Jacobian.prototype.__varz = function() { + this.linearA = new b2Vec2; + this.linearB = new b2Vec2 +}; +b2Jacobian.prototype.SetZero = function() { + this.linearA.SetZero(); + this.angularA = 0; + this.linearB.SetZero(); + this.angularB = 0 +}; +b2Jacobian.prototype.Set = function(x1, a1, x2, a2) { + this.linearA.SetV(x1); + this.angularA = a1; + this.linearB.SetV(x2); + this.angularB = a2 +}; +b2Jacobian.prototype.Compute = function(x1, a1, x2, a2) { + return this.linearA.x * x1.x + this.linearA.y * x1.y + this.angularA * a1 + (this.linearB.x * x2.x + this.linearB.y * x2.y) + this.angularB * a2 +}; +b2Jacobian.prototype.linearA = new b2Vec2; +b2Jacobian.prototype.angularA = null; +b2Jacobian.prototype.linearB = new b2Vec2; +b2Jacobian.prototype.angularB = null;var b2Bound = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Bound.prototype.__constructor = function() { +}; +b2Bound.prototype.__varz = function() { +}; +b2Bound.prototype.IsLower = function() { + return(this.value & 1) == 0 +}; +b2Bound.prototype.IsUpper = function() { + return(this.value & 1) == 1 +}; +b2Bound.prototype.Swap = function(b) { + var tempValue = this.value; + var tempProxy = this.proxy; + var tempStabbingCount = this.stabbingCount; + this.value = b.value; + this.proxy = b.proxy; + this.stabbingCount = b.stabbingCount; + b.value = tempValue; + b.proxy = tempProxy; + b.stabbingCount = tempStabbingCount +}; +b2Bound.prototype.value = 0; +b2Bound.prototype.proxy = null; +b2Bound.prototype.stabbingCount = 0;var b2SimplexVertex = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2SimplexVertex.prototype.__constructor = function() { +}; +b2SimplexVertex.prototype.__varz = function() { +}; +b2SimplexVertex.prototype.Set = function(other) { + this.wA.SetV(other.wA); + this.wB.SetV(other.wB); + this.w.SetV(other.w); + this.a = other.a; + this.indexA = other.indexA; + this.indexB = other.indexB +}; +b2SimplexVertex.prototype.wA = null; +b2SimplexVertex.prototype.wB = null; +b2SimplexVertex.prototype.w = null; +b2SimplexVertex.prototype.a = null; +b2SimplexVertex.prototype.indexA = 0; +b2SimplexVertex.prototype.indexB = 0;var b2Mat22 = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Mat22.prototype.__constructor = function() { + this.col1.x = this.col2.y = 1 +}; +b2Mat22.prototype.__varz = function() { + this.col1 = new b2Vec2; + this.col2 = new b2Vec2 +}; +b2Mat22.FromAngle = function(angle) { + var mat = new b2Mat22; + mat.Set(angle); + return mat +}; +b2Mat22.FromVV = function(c1, c2) { + var mat = new b2Mat22; + mat.SetVV(c1, c2); + return mat +}; +b2Mat22.prototype.Set = function(angle) { + var c = Math.cos(angle); + var s = Math.sin(angle); + this.col1.x = c; + this.col2.x = -s; + this.col1.y = s; + this.col2.y = c +}; +b2Mat22.prototype.SetVV = function(c1, c2) { + this.col1.SetV(c1); + this.col2.SetV(c2) +}; +b2Mat22.prototype.Copy = function() { + var mat = new b2Mat22; + mat.SetM(this); + return mat +}; +b2Mat22.prototype.SetM = function(m) { + this.col1.SetV(m.col1); + this.col2.SetV(m.col2) +}; +b2Mat22.prototype.AddM = function(m) { + this.col1.x += m.col1.x; + this.col1.y += m.col1.y; + this.col2.x += m.col2.x; + this.col2.y += m.col2.y +}; +b2Mat22.prototype.SetIdentity = function() { + this.col1.x = 1; + this.col2.x = 0; + this.col1.y = 0; + this.col2.y = 1 +}; +b2Mat22.prototype.SetZero = function() { + this.col1.x = 0; + this.col2.x = 0; + this.col1.y = 0; + this.col2.y = 0 +}; +b2Mat22.prototype.GetAngle = function() { + return Math.atan2(this.col1.y, this.col1.x) +}; +b2Mat22.prototype.GetInverse = function(out) { + var a = this.col1.x; + var b = this.col2.x; + var c = this.col1.y; + var d = this.col2.y; + var det = a * d - b * c; + if(det != 0) { + det = 1 / det + } + out.col1.x = det * d; + out.col2.x = -det * b; + out.col1.y = -det * c; + out.col2.y = det * a; + return out +}; +b2Mat22.prototype.Solve = function(out, bX, bY) { + var a11 = this.col1.x; + var a12 = this.col2.x; + var a21 = this.col1.y; + var a22 = this.col2.y; + var det = a11 * a22 - a12 * a21; + if(det != 0) { + det = 1 / det + } + out.x = det * (a22 * bX - a12 * bY); + out.y = det * (a11 * bY - a21 * bX); + return out +}; +b2Mat22.prototype.Abs = function() { + this.col1.Abs(); + this.col2.Abs() +}; +b2Mat22.prototype.col1 = new b2Vec2; +b2Mat22.prototype.col2 = new b2Vec2;var b2SimplexCache = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2SimplexCache.prototype.__constructor = function() { +}; +b2SimplexCache.prototype.__varz = function() { + this.indexA = new Array(3); + this.indexB = new Array(3) +}; +b2SimplexCache.prototype.metric = null; +b2SimplexCache.prototype.count = 0; +b2SimplexCache.prototype.indexA = new Array(3); +b2SimplexCache.prototype.indexB = new Array(3);var b2Shape = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Shape.prototype.__constructor = function() { + this.m_type = b2Shape.e_unknownShape; + this.m_radius = b2Settings.b2_linearSlop +}; +b2Shape.prototype.__varz = function() { +}; +b2Shape.TestOverlap = function(shape1, transform1, shape2, transform2) { + var input = new b2DistanceInput; + input.proxyA = new b2DistanceProxy; + input.proxyA.Set(shape1); + input.proxyB = new b2DistanceProxy; + input.proxyB.Set(shape2); + input.transformA = transform1; + input.transformB = transform2; + input.useRadii = true; + var simplexCache = new b2SimplexCache; + simplexCache.count = 0; + var output = new b2DistanceOutput; + b2Distance.Distance(output, simplexCache, input); + return output.distance < 10 * Number.MIN_VALUE +}; +b2Shape.e_hitCollide = 1; +b2Shape.e_missCollide = 0; +b2Shape.e_startsInsideCollide = -1; +b2Shape.e_unknownShape = -1; +b2Shape.e_circleShape = 0; +b2Shape.e_polygonShape = 1; +b2Shape.e_edgeShape = 2; +b2Shape.e_shapeTypeCount = 3; +b2Shape.prototype.Copy = function() { + return null +}; +b2Shape.prototype.Set = function(other) { + this.m_radius = other.m_radius +}; +b2Shape.prototype.GetType = function() { + return this.m_type +}; +b2Shape.prototype.TestPoint = function(xf, p) { + return false +}; +b2Shape.prototype.RayCast = function(output, input, transform) { + return false +}; +b2Shape.prototype.ComputeAABB = function(aabb, xf) { +}; +b2Shape.prototype.ComputeMass = function(massData, density) { +}; +b2Shape.prototype.ComputeSubmergedArea = function(normal, offset, xf, c) { + return 0 +}; +b2Shape.prototype.m_type = 0; +b2Shape.prototype.m_radius = null;var b2Segment = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Segment.prototype.__constructor = function() { +}; +b2Segment.prototype.__varz = function() { + this.p1 = new b2Vec2; + this.p2 = new b2Vec2 +}; +b2Segment.prototype.TestSegment = function(lambda, normal, segment, maxLambda) { + var s = segment.p1; + var rX = segment.p2.x - s.x; + var rY = segment.p2.y - s.y; + var dX = this.p2.x - this.p1.x; + var dY = this.p2.y - this.p1.y; + var nX = dY; + var nY = -dX; + var k_slop = 100 * Number.MIN_VALUE; + var denom = -(rX * nX + rY * nY); + if(denom > k_slop) { + var bX = s.x - this.p1.x; + var bY = s.y - this.p1.y; + var a = bX * nX + bY * nY; + if(0 <= a && a <= maxLambda * denom) { + var mu2 = -rX * bY + rY * bX; + if(-k_slop * denom <= mu2 && mu2 <= denom * (1 + k_slop)) { + a /= denom; + var nLen = Math.sqrt(nX * nX + nY * nY); + nX /= nLen; + nY /= nLen; + lambda[0] = a; + normal.Set(nX, nY); + return true + } + } + } + return false +}; +b2Segment.prototype.Extend = function(aabb) { + this.ExtendForward(aabb); + this.ExtendBackward(aabb) +}; +b2Segment.prototype.ExtendForward = function(aabb) { + var dX = this.p2.x - this.p1.x; + var dY = this.p2.y - this.p1.y; + var lambda = Math.min(dX > 0 ? (aabb.upperBound.x - this.p1.x) / dX : dX < 0 ? (aabb.lowerBound.x - this.p1.x) / dX : Number.POSITIVE_INFINITY, dY > 0 ? (aabb.upperBound.y - this.p1.y) / dY : dY < 0 ? (aabb.lowerBound.y - this.p1.y) / dY : Number.POSITIVE_INFINITY); + this.p2.x = this.p1.x + dX * lambda; + this.p2.y = this.p1.y + dY * lambda +}; +b2Segment.prototype.ExtendBackward = function(aabb) { + var dX = -this.p2.x + this.p1.x; + var dY = -this.p2.y + this.p1.y; + var lambda = Math.min(dX > 0 ? (aabb.upperBound.x - this.p2.x) / dX : dX < 0 ? (aabb.lowerBound.x - this.p2.x) / dX : Number.POSITIVE_INFINITY, dY > 0 ? (aabb.upperBound.y - this.p2.y) / dY : dY < 0 ? (aabb.lowerBound.y - this.p2.y) / dY : Number.POSITIVE_INFINITY); + this.p1.x = this.p2.x + dX * lambda; + this.p1.y = this.p2.y + dY * lambda +}; +b2Segment.prototype.p1 = new b2Vec2; +b2Segment.prototype.p2 = new b2Vec2;var b2ContactRegister = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactRegister.prototype.__constructor = function() { +}; +b2ContactRegister.prototype.__varz = function() { +}; +b2ContactRegister.prototype.createFcn = null; +b2ContactRegister.prototype.destroyFcn = null; +b2ContactRegister.prototype.primary = null; +b2ContactRegister.prototype.pool = null; +b2ContactRegister.prototype.poolCount = 0;var b2DebugDraw = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DebugDraw.prototype.__constructor = function() { + this.m_drawFlags = 0 +}; +b2DebugDraw.prototype.__varz = function() { +}; +b2DebugDraw.e_shapeBit = 1; +b2DebugDraw.e_jointBit = 2; +b2DebugDraw.e_aabbBit = 4; +b2DebugDraw.e_pairBit = 8; +b2DebugDraw.e_centerOfMassBit = 16; +b2DebugDraw.e_controllerBit = 32; +b2DebugDraw.prototype.SetFlags = function(flags) { + this.m_drawFlags = flags +}; +b2DebugDraw.prototype.GetFlags = function() { + return this.m_drawFlags +}; +b2DebugDraw.prototype.AppendFlags = function(flags) { + this.m_drawFlags |= flags +}; +b2DebugDraw.prototype.ClearFlags = function(flags) { + this.m_drawFlags &= ~flags +}; +b2DebugDraw.prototype.SetSprite = function(sprite) { + this.m_sprite = sprite +}; +b2DebugDraw.prototype.GetSprite = function() { + return this.m_sprite +}; +b2DebugDraw.prototype.SetDrawScale = function(drawScale) { + this.m_drawScale = drawScale +}; +b2DebugDraw.prototype.GetDrawScale = function() { + return this.m_drawScale +}; +b2DebugDraw.prototype.SetLineThickness = function(lineThickness) { + this.m_lineThickness = lineThickness +}; +b2DebugDraw.prototype.GetLineThickness = function() { + return this.m_lineThickness +}; +b2DebugDraw.prototype.SetAlpha = function(alpha) { + this.m_alpha = alpha +}; +b2DebugDraw.prototype.GetAlpha = function() { + return this.m_alpha +}; +b2DebugDraw.prototype.SetFillAlpha = function(alpha) { + this.m_fillAlpha = alpha +}; +b2DebugDraw.prototype.GetFillAlpha = function() { + return this.m_fillAlpha +}; +b2DebugDraw.prototype.SetXFormScale = function(xformScale) { + this.m_xformScale = xformScale +}; +b2DebugDraw.prototype.GetXFormScale = function() { + return this.m_xformScale +}; +b2DebugDraw.prototype.Clear = function() { + this.m_sprite.clearRect(0, 0, this.m_sprite.canvas.width, this.m_sprite.canvas.height) +}; +b2DebugDraw.prototype.Y = function(y) { + return this.m_sprite.canvas.height - y +}; +b2DebugDraw.prototype.ToWorldPoint = function(localPoint) { + return new b2Vec2(localPoint.x / this.m_drawScale, this.Y(localPoint.y) / this.m_drawScale) +}; +b2DebugDraw.prototype.ColorStyle = function(color, alpha) { + return"rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + alpha + ")" +}; +b2DebugDraw.prototype.DrawPolygon = function(vertices, vertexCount, color) { + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.moveTo(vertices[0].x * this.m_drawScale, vertices[0].y * this.m_drawScale); + for(var i = 1;i < vertexCount;i++) { + this.m_sprite.graphics.lineTo(vertices[i].x * this.m_drawScale, vertices[i].y * this.m_drawScale) + } + this.m_sprite.graphics.lineTo(vertices[0].x * this.m_drawScale, vertices[0].y * this.m_drawScale) +}; +b2DebugDraw.prototype.DrawSolidPolygon = function(vertices, vertexCount, color) { + this.m_sprite.strokeSyle = this.ColorStyle(color, this.m_alpha); + this.m_sprite.lineWidth = this.m_lineThickness; + this.m_sprite.fillStyle = this.ColorStyle(color, this.m_fillAlpha); + this.m_sprite.beginPath(); + this.m_sprite.moveTo(vertices[0].x * this.m_drawScale, this.Y(vertices[0].y * this.m_drawScale)); + for(var i = 1;i < vertexCount;i++) { + this.m_sprite.lineTo(vertices[i].x * this.m_drawScale, this.Y(vertices[i].y * this.m_drawScale)) + } + this.m_sprite.lineTo(vertices[0].x * this.m_drawScale, this.Y(vertices[0].y * this.m_drawScale)); + this.m_sprite.fill(); + this.m_sprite.stroke(); + this.m_sprite.closePath() +}; +b2DebugDraw.prototype.DrawCircle = function(center, radius, color) { + this.m_sprite.graphics.lineStyle(this.m_lineThickness, color.color, this.m_alpha); + this.m_sprite.graphics.drawCircle(center.x * this.m_drawScale, center.y * this.m_drawScale, radius * this.m_drawScale) +}; +b2DebugDraw.prototype.DrawSolidCircle = function(center, radius, axis, color) { + this.m_sprite.strokeSyle = this.ColorStyle(color, this.m_alpha); + this.m_sprite.lineWidth = this.m_lineThickness; + this.m_sprite.fillStyle = this.ColorStyle(color, this.m_fillAlpha); + this.m_sprite.beginPath(); + this.m_sprite.arc(center.x * this.m_drawScale, this.Y(center.y * this.m_drawScale), radius * this.m_drawScale, 0, Math.PI * 2, true); + this.m_sprite.fill(); + this.m_sprite.stroke(); + this.m_sprite.closePath() +}; +b2DebugDraw.prototype.DrawSegment = function(p1, p2, color) { + this.m_sprite.lineWidth = this.m_lineThickness; + this.m_sprite.strokeSyle = this.ColorStyle(color, this.m_alpha); + this.m_sprite.beginPath(); + this.m_sprite.moveTo(p1.x * this.m_drawScale, this.Y(p1.y * this.m_drawScale)); + this.m_sprite.lineTo(p2.x * this.m_drawScale, this.Y(p2.y * this.m_drawScale)); + this.m_sprite.stroke(); + this.m_sprite.closePath() +}; +b2DebugDraw.prototype.DrawTransform = function(xf) { + this.m_sprite.lineWidth = this.m_lineThickness; + this.m_sprite.strokeSyle = this.ColorStyle(new b2Color(255, 0, 0), this.m_alpha); + this.m_sprite.beginPath(); + this.m_sprite.moveTo(xf.position.x * this.m_drawScale, this.Y(xf.position.y * this.m_drawScale)); + this.m_sprite.lineTo((xf.position.x + this.m_xformScale * xf.R.col1.x) * this.m_drawScale, this.Y((xf.position.y + this.m_xformScale * xf.R.col1.y) * this.m_drawScale)); + this.m_sprite.stroke(); + this.m_sprite.closePath(); + this.m_sprite.strokeSyle = this.ColorStyle(new b2Color(0, 255, 0), this.m_alpha); + this.m_sprite.beginPath(); + this.m_sprite.moveTo(xf.position.x * this.m_drawScale, this.Y(xf.position.y * this.m_drawScale)); + this.m_sprite.lineTo((xf.position.x + this.m_xformScale * xf.R.col2.x) * this.m_drawScale, this.Y((xf.position.y + this.m_xformScale * xf.R.col2.y) * this.m_drawScale)); + this.m_sprite.stroke(); + this.m_sprite.closePath() +}; +b2DebugDraw.prototype.m_drawFlags = 0; +b2DebugDraw.prototype.m_sprite = null; +b2DebugDraw.prototype.m_drawScale = 1; +b2DebugDraw.prototype.m_lineThickness = 1; +b2DebugDraw.prototype.m_alpha = 1; +b2DebugDraw.prototype.m_fillAlpha = 1; +b2DebugDraw.prototype.m_xformScale = 1;var b2Sweep = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Sweep.prototype.__constructor = function() { +}; +b2Sweep.prototype.__varz = function() { + this.localCenter = new b2Vec2; + this.c0 = new b2Vec2; + this.c = new b2Vec2 +}; +b2Sweep.prototype.Set = function(other) { + this.localCenter.SetV(other.localCenter); + this.c0.SetV(other.c0); + this.c.SetV(other.c); + this.a0 = other.a0; + this.a = other.a; + this.t0 = other.t0 +}; +b2Sweep.prototype.Copy = function() { + var copy = new b2Sweep; + copy.localCenter.SetV(this.localCenter); + copy.c0.SetV(this.c0); + copy.c.SetV(this.c); + copy.a0 = this.a0; + copy.a = this.a; + copy.t0 = this.t0; + return copy +}; +b2Sweep.prototype.GetTransform = function(xf, alpha) { + xf.position.x = (1 - alpha) * this.c0.x + alpha * this.c.x; + xf.position.y = (1 - alpha) * this.c0.y + alpha * this.c.y; + var angle = (1 - alpha) * this.a0 + alpha * this.a; + xf.R.Set(angle); + var tMat = xf.R; + xf.position.x -= tMat.col1.x * this.localCenter.x + tMat.col2.x * this.localCenter.y; + xf.position.y -= tMat.col1.y * this.localCenter.x + tMat.col2.y * this.localCenter.y +}; +b2Sweep.prototype.Advance = function(t) { + if(this.t0 < t && 1 - this.t0 > Number.MIN_VALUE) { + var alpha = (t - this.t0) / (1 - this.t0); + this.c0.x = (1 - alpha) * this.c0.x + alpha * this.c.x; + this.c0.y = (1 - alpha) * this.c0.y + alpha * this.c.y; + this.a0 = (1 - alpha) * this.a0 + alpha * this.a; + this.t0 = t + } +}; +b2Sweep.prototype.localCenter = new b2Vec2; +b2Sweep.prototype.c0 = new b2Vec2; +b2Sweep.prototype.c = new b2Vec2; +b2Sweep.prototype.a0 = null; +b2Sweep.prototype.a = null; +b2Sweep.prototype.t0 = null;var b2DistanceOutput = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DistanceOutput.prototype.__constructor = function() { +}; +b2DistanceOutput.prototype.__varz = function() { + this.pointA = new b2Vec2; + this.pointB = new b2Vec2 +}; +b2DistanceOutput.prototype.pointA = new b2Vec2; +b2DistanceOutput.prototype.pointB = new b2Vec2; +b2DistanceOutput.prototype.distance = null; +b2DistanceOutput.prototype.iterations = 0;var b2Mat33 = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Mat33.prototype.__constructor = function(c1, c2, c3) { + if(!c1 && !c2 && !c3) { + this.col1.SetZero(); + this.col2.SetZero(); + this.col3.SetZero() + }else { + this.col1.SetV(c1); + this.col2.SetV(c2); + this.col3.SetV(c3) + } +}; +b2Mat33.prototype.__varz = function() { + this.col1 = new b2Vec3; + this.col2 = new b2Vec3; + this.col3 = new b2Vec3 +}; +b2Mat33.prototype.SetVVV = function(c1, c2, c3) { + this.col1.SetV(c1); + this.col2.SetV(c2); + this.col3.SetV(c3) +}; +b2Mat33.prototype.Copy = function() { + return new b2Mat33(this.col1, this.col2, this.col3) +}; +b2Mat33.prototype.SetM = function(m) { + this.col1.SetV(m.col1); + this.col2.SetV(m.col2); + this.col3.SetV(m.col3) +}; +b2Mat33.prototype.AddM = function(m) { + this.col1.x += m.col1.x; + this.col1.y += m.col1.y; + this.col1.z += m.col1.z; + this.col2.x += m.col2.x; + this.col2.y += m.col2.y; + this.col2.z += m.col2.z; + this.col3.x += m.col3.x; + this.col3.y += m.col3.y; + this.col3.z += m.col3.z +}; +b2Mat33.prototype.SetIdentity = function() { + this.col1.x = 1; + this.col2.x = 0; + this.col3.x = 0; + this.col1.y = 0; + this.col2.y = 1; + this.col3.y = 0; + this.col1.z = 0; + this.col2.z = 0; + this.col3.z = 1 +}; +b2Mat33.prototype.SetZero = function() { + this.col1.x = 0; + this.col2.x = 0; + this.col3.x = 0; + this.col1.y = 0; + this.col2.y = 0; + this.col3.y = 0; + this.col1.z = 0; + this.col2.z = 0; + this.col3.z = 0 +}; +b2Mat33.prototype.Solve22 = function(out, bX, bY) { + var a11 = this.col1.x; + var a12 = this.col2.x; + var a21 = this.col1.y; + var a22 = this.col2.y; + var det = a11 * a22 - a12 * a21; + if(det != 0) { + det = 1 / det + } + out.x = det * (a22 * bX - a12 * bY); + out.y = det * (a11 * bY - a21 * bX); + return out +}; +b2Mat33.prototype.Solve33 = function(out, bX, bY, bZ) { + var a11 = this.col1.x; + var a21 = this.col1.y; + var a31 = this.col1.z; + var a12 = this.col2.x; + var a22 = this.col2.y; + var a32 = this.col2.z; + var a13 = this.col3.x; + var a23 = this.col3.y; + var a33 = this.col3.z; + var det = a11 * (a22 * a33 - a32 * a23) + a21 * (a32 * a13 - a12 * a33) + a31 * (a12 * a23 - a22 * a13); + if(det != 0) { + det = 1 / det + } + out.x = det * (bX * (a22 * a33 - a32 * a23) + bY * (a32 * a13 - a12 * a33) + bZ * (a12 * a23 - a22 * a13)); + out.y = det * (a11 * (bY * a33 - bZ * a23) + a21 * (bZ * a13 - bX * a33) + a31 * (bX * a23 - bY * a13)); + out.z = det * (a11 * (a22 * bZ - a32 * bY) + a21 * (a32 * bX - a12 * bZ) + a31 * (a12 * bY - a22 * bX)); + return out +}; +b2Mat33.prototype.col1 = new b2Vec3; +b2Mat33.prototype.col2 = new b2Vec3; +b2Mat33.prototype.col3 = new b2Vec3;var b2PositionSolverManifold = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2PositionSolverManifold.prototype.__constructor = function() { + this.m_normal = new b2Vec2; + this.m_separations = new Array(b2Settings.b2_maxManifoldPoints); + this.m_points = new Array(b2Settings.b2_maxManifoldPoints); + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;i++) { + this.m_points[i] = new b2Vec2 + } +}; +b2PositionSolverManifold.prototype.__varz = function() { +}; +b2PositionSolverManifold.circlePointA = new b2Vec2; +b2PositionSolverManifold.circlePointB = new b2Vec2; +b2PositionSolverManifold.prototype.Initialize = function(cc) { + b2Settings.b2Assert(cc.pointCount > 0); + var i = 0; + var clipPointX; + var clipPointY; + var tMat; + var tVec; + var planePointX; + var planePointY; + switch(cc.type) { + case b2Manifold.e_circles: + tMat = cc.bodyA.m_xf.R; + tVec = cc.localPoint; + var pointAX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var pointAY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = cc.bodyB.m_xf.R; + tVec = cc.points[0].localPoint; + var pointBX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var pointBY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var dX = pointBX - pointAX; + var dY = pointBY - pointAY; + var d2 = dX * dX + dY * dY; + if(d2 > Number.MIN_VALUE * Number.MIN_VALUE) { + var d = Math.sqrt(d2); + this.m_normal.x = dX / d; + this.m_normal.y = dY / d + }else { + this.m_normal.x = 1; + this.m_normal.y = 0 + } + this.m_points[0].x = 0.5 * (pointAX + pointBX); + this.m_points[0].y = 0.5 * (pointAY + pointBY); + this.m_separations[0] = dX * this.m_normal.x + dY * this.m_normal.y - cc.radius; + break; + case b2Manifold.e_faceA: + tMat = cc.bodyA.m_xf.R; + tVec = cc.localPlaneNormal; + this.m_normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + this.m_normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = cc.bodyA.m_xf.R; + tVec = cc.localPoint; + planePointX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + planePointY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = cc.bodyB.m_xf.R; + for(i = 0;i < cc.pointCount;++i) { + tVec = cc.points[i].localPoint; + clipPointX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + clipPointY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_separations[i] = (clipPointX - planePointX) * this.m_normal.x + (clipPointY - planePointY) * this.m_normal.y - cc.radius; + this.m_points[i].x = clipPointX; + this.m_points[i].y = clipPointY + } + break; + case b2Manifold.e_faceB: + tMat = cc.bodyB.m_xf.R; + tVec = cc.localPlaneNormal; + this.m_normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + this.m_normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = cc.bodyB.m_xf.R; + tVec = cc.localPoint; + planePointX = cc.bodyB.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + planePointY = cc.bodyB.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = cc.bodyA.m_xf.R; + for(i = 0;i < cc.pointCount;++i) { + tVec = cc.points[i].localPoint; + clipPointX = cc.bodyA.m_xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + clipPointY = cc.bodyA.m_xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + this.m_separations[i] = (clipPointX - planePointX) * this.m_normal.x + (clipPointY - planePointY) * this.m_normal.y - cc.radius; + this.m_points[i].Set(clipPointX, clipPointY) + } + this.m_normal.x *= -1; + this.m_normal.y *= -1; + break + } +}; +b2PositionSolverManifold.prototype.m_normal = null; +b2PositionSolverManifold.prototype.m_points = null; +b2PositionSolverManifold.prototype.m_separations = null;var b2OBB = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2OBB.prototype.__constructor = function() { +}; +b2OBB.prototype.__varz = function() { + this.R = new b2Mat22; + this.center = new b2Vec2; + this.extents = new b2Vec2 +}; +b2OBB.prototype.R = new b2Mat22; +b2OBB.prototype.center = new b2Vec2; +b2OBB.prototype.extents = new b2Vec2;var b2Pair = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Pair.prototype.__constructor = function() { +}; +b2Pair.prototype.__varz = function() { +}; +b2Pair.b2_nullProxy = b2Settings.USHRT_MAX; +b2Pair.e_pairBuffered = 1; +b2Pair.e_pairRemoved = 2; +b2Pair.e_pairFinal = 4; +b2Pair.prototype.SetBuffered = function() { + this.status |= b2Pair.e_pairBuffered +}; +b2Pair.prototype.ClearBuffered = function() { + this.status &= ~b2Pair.e_pairBuffered +}; +b2Pair.prototype.IsBuffered = function() { + return(this.status & b2Pair.e_pairBuffered) == b2Pair.e_pairBuffered +}; +b2Pair.prototype.SetRemoved = function() { + this.status |= b2Pair.e_pairRemoved +}; +b2Pair.prototype.ClearRemoved = function() { + this.status &= ~b2Pair.e_pairRemoved +}; +b2Pair.prototype.IsRemoved = function() { + return(this.status & b2Pair.e_pairRemoved) == b2Pair.e_pairRemoved +}; +b2Pair.prototype.SetFinal = function() { + this.status |= b2Pair.e_pairFinal +}; +b2Pair.prototype.IsFinal = function() { + return(this.status & b2Pair.e_pairFinal) == b2Pair.e_pairFinal +}; +b2Pair.prototype.userData = null; +b2Pair.prototype.proxy1 = null; +b2Pair.prototype.proxy2 = null; +b2Pair.prototype.next = null; +b2Pair.prototype.status = 0;var b2FixtureDef = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2FixtureDef.prototype.__constructor = function() { + this.shape = null; + this.userData = null; + this.friction = 0.2; + this.restitution = 0; + this.density = 0; + this.filter.categoryBits = 1; + this.filter.maskBits = 65535; + this.filter.groupIndex = 0; + this.isSensor = false +}; +b2FixtureDef.prototype.__varz = function() { + this.filter = new b2FilterData +}; +b2FixtureDef.prototype.shape = null; +b2FixtureDef.prototype.userData = null; +b2FixtureDef.prototype.friction = null; +b2FixtureDef.prototype.restitution = null; +b2FixtureDef.prototype.density = null; +b2FixtureDef.prototype.isSensor = null; +b2FixtureDef.prototype.filter = new b2FilterData;var b2ContactID = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactID.prototype.__constructor = function() { + this.features._m_id = this +}; +b2ContactID.prototype.__varz = function() { + this.features = new Features +}; +b2ContactID.prototype.Set = function(id) { + key = id._key +}; +b2ContactID.prototype.Copy = function() { + var id = new b2ContactID; + id.key = key; + return id +}; +b2ContactID.prototype.__defineSetter__("key", function() { + return this._key +}); +b2ContactID.prototype.__defineSetter__("key", function(value) { + this._key = value; + this.features._referenceEdge = this._key & 255; + this.features._incidentEdge = (this._key & 65280) >> 8 & 255; + this.features._incidentVertex = (this._key & 16711680) >> 16 & 255; + this.features._flip = (this._key & 4278190080) >> 24 & 255 +}); +b2ContactID.prototype._key = 0; +b2ContactID.prototype.features = new Features;var b2Transform = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Transform.prototype.__constructor = function(pos, r) { + if(pos) { + this.position.SetV(pos); + this.R.SetM(r) + } +}; +b2Transform.prototype.__varz = function() { + this.position = new b2Vec2; + this.R = new b2Mat22 +}; +b2Transform.prototype.Initialize = function(pos, r) { + this.position.SetV(pos); + this.R.SetM(r) +}; +b2Transform.prototype.SetIdentity = function() { + this.position.SetZero(); + this.R.SetIdentity() +}; +b2Transform.prototype.Set = function(x) { + this.position.SetV(x.position); + this.R.SetM(x.R) +}; +b2Transform.prototype.GetAngle = function() { + return Math.atan2(this.R.col1.y, this.R.col1.x) +}; +b2Transform.prototype.position = new b2Vec2; +b2Transform.prototype.R = new b2Mat22;var b2EdgeShape = function() { + b2Shape.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2EdgeShape.prototype, b2Shape.prototype); +b2EdgeShape.prototype._super = b2Shape.prototype; +b2EdgeShape.prototype.__constructor = function(v1, v2) { + this._super.__constructor.apply(this, []); + this.m_type = b2Shape.e_edgeShape; + this.m_prevEdge = null; + this.m_nextEdge = null; + this.m_v1 = v1; + this.m_v2 = v2; + this.m_direction.Set(this.m_v2.x - this.m_v1.x, this.m_v2.y - this.m_v1.y); + this.m_length = this.m_direction.Normalize(); + this.m_normal.Set(this.m_direction.y, -this.m_direction.x); + this.m_coreV1.Set(-b2Settings.b2_toiSlop * (this.m_normal.x - this.m_direction.x) + this.m_v1.x, -b2Settings.b2_toiSlop * (this.m_normal.y - this.m_direction.y) + this.m_v1.y); + this.m_coreV2.Set(-b2Settings.b2_toiSlop * (this.m_normal.x + this.m_direction.x) + this.m_v2.x, -b2Settings.b2_toiSlop * (this.m_normal.y + this.m_direction.y) + this.m_v2.y); + this.m_cornerDir1 = this.m_normal; + this.m_cornerDir2.Set(-this.m_normal.x, -this.m_normal.y) +}; +b2EdgeShape.prototype.__varz = function() { + this.s_supportVec = new b2Vec2; + this.m_v1 = new b2Vec2; + this.m_v2 = new b2Vec2; + this.m_coreV1 = new b2Vec2; + this.m_coreV2 = new b2Vec2; + this.m_normal = new b2Vec2; + this.m_direction = new b2Vec2; + this.m_cornerDir1 = new b2Vec2; + this.m_cornerDir2 = new b2Vec2 +}; +b2EdgeShape.prototype.SetPrevEdge = function(edge, core, cornerDir, convex) { + this.m_prevEdge = edge; + this.m_coreV1 = core; + this.m_cornerDir1 = cornerDir; + this.m_cornerConvex1 = convex +}; +b2EdgeShape.prototype.SetNextEdge = function(edge, core, cornerDir, convex) { + this.m_nextEdge = edge; + this.m_coreV2 = core; + this.m_cornerDir2 = cornerDir; + this.m_cornerConvex2 = convex +}; +b2EdgeShape.prototype.TestPoint = function(transform, p) { + return false +}; +b2EdgeShape.prototype.RayCast = function(output, input, transform) { + var tMat; + var rX = input.p2.x - input.p1.x; + var rY = input.p2.y - input.p1.y; + tMat = transform.R; + var v1X = transform.position.x + (tMat.col1.x * this.m_v1.x + tMat.col2.x * this.m_v1.y); + var v1Y = transform.position.y + (tMat.col1.y * this.m_v1.x + tMat.col2.y * this.m_v1.y); + var nX = transform.position.y + (tMat.col1.y * this.m_v2.x + tMat.col2.y * this.m_v2.y) - v1Y; + var nY = -(transform.position.x + (tMat.col1.x * this.m_v2.x + tMat.col2.x * this.m_v2.y) - v1X); + var k_slop = 100 * Number.MIN_VALUE; + var denom = -(rX * nX + rY * nY); + if(denom > k_slop) { + var bX = input.p1.x - v1X; + var bY = input.p1.y - v1Y; + var a = bX * nX + bY * nY; + if(0 <= a && a <= input.maxFraction * denom) { + var mu2 = -rX * bY + rY * bX; + if(-k_slop * denom <= mu2 && mu2 <= denom * (1 + k_slop)) { + a /= denom; + output.fraction = a; + var nLen = Math.sqrt(nX * nX + nY * nY); + output.normal.x = nX / nLen; + output.normal.y = nY / nLen; + return true + } + } + } + return false +}; +b2EdgeShape.prototype.ComputeAABB = function(aabb, transform) { + var tMat = transform.R; + var v1X = transform.position.x + (tMat.col1.x * this.m_v1.x + tMat.col2.x * this.m_v1.y); + var v1Y = transform.position.y + (tMat.col1.y * this.m_v1.x + tMat.col2.y * this.m_v1.y); + var v2X = transform.position.x + (tMat.col1.x * this.m_v2.x + tMat.col2.x * this.m_v2.y); + var v2Y = transform.position.y + (tMat.col1.y * this.m_v2.x + tMat.col2.y * this.m_v2.y); + if(v1X < v2X) { + aabb.lowerBound.x = v1X; + aabb.upperBound.x = v2X + }else { + aabb.lowerBound.x = v2X; + aabb.upperBound.x = v1X + } + if(v1Y < v2Y) { + aabb.lowerBound.y = v1Y; + aabb.upperBound.y = v2Y + }else { + aabb.lowerBound.y = v2Y; + aabb.upperBound.y = v1Y + } +}; +b2EdgeShape.prototype.ComputeMass = function(massData, density) { + massData.mass = 0; + massData.center.SetV(this.m_v1); + massData.I = 0 +}; +b2EdgeShape.prototype.ComputeSubmergedArea = function(normal, offset, xf, c) { + var v0 = new b2Vec2(normal.x * offset, normal.y * offset); + var v1 = b2Math.MulX(xf, this.m_v1); + var v2 = b2Math.MulX(xf, this.m_v2); + var d1 = b2Math.Dot(normal, v1) - offset; + var d2 = b2Math.Dot(normal, v2) - offset; + if(d1 > 0) { + if(d2 > 0) { + return 0 + }else { + v1.x = -d2 / (d1 - d2) * v1.x + d1 / (d1 - d2) * v2.x; + v1.y = -d2 / (d1 - d2) * v1.y + d1 / (d1 - d2) * v2.y + } + }else { + if(d2 > 0) { + v2.x = -d2 / (d1 - d2) * v1.x + d1 / (d1 - d2) * v2.x; + v2.y = -d2 / (d1 - d2) * v1.y + d1 / (d1 - d2) * v2.y + }else { + } + } + c.x = (v0.x + v1.x + v2.x) / 3; + c.y = (v0.y + v1.y + v2.y) / 3; + return 0.5 * ((v1.x - v0.x) * (v2.y - v0.y) - (v1.y - v0.y) * (v2.x - v0.x)) +}; +b2EdgeShape.prototype.GetLength = function() { + return this.m_length +}; +b2EdgeShape.prototype.GetVertex1 = function() { + return this.m_v1 +}; +b2EdgeShape.prototype.GetVertex2 = function() { + return this.m_v2 +}; +b2EdgeShape.prototype.GetCoreVertex1 = function() { + return this.m_coreV1 +}; +b2EdgeShape.prototype.GetCoreVertex2 = function() { + return this.m_coreV2 +}; +b2EdgeShape.prototype.GetNormalVector = function() { + return this.m_normal +}; +b2EdgeShape.prototype.GetDirectionVector = function() { + return this.m_direction +}; +b2EdgeShape.prototype.GetCorner1Vector = function() { + return this.m_cornerDir1 +}; +b2EdgeShape.prototype.GetCorner2Vector = function() { + return this.m_cornerDir2 +}; +b2EdgeShape.prototype.Corner1IsConvex = function() { + return this.m_cornerConvex1 +}; +b2EdgeShape.prototype.Corner2IsConvex = function() { + return this.m_cornerConvex2 +}; +b2EdgeShape.prototype.GetFirstVertex = function(xf) { + var tMat = xf.R; + return new b2Vec2(xf.position.x + (tMat.col1.x * this.m_coreV1.x + tMat.col2.x * this.m_coreV1.y), xf.position.y + (tMat.col1.y * this.m_coreV1.x + tMat.col2.y * this.m_coreV1.y)) +}; +b2EdgeShape.prototype.GetNextEdge = function() { + return this.m_nextEdge +}; +b2EdgeShape.prototype.GetPrevEdge = function() { + return this.m_prevEdge +}; +b2EdgeShape.prototype.Support = function(xf, dX, dY) { + var tMat = xf.R; + var v1X = xf.position.x + (tMat.col1.x * this.m_coreV1.x + tMat.col2.x * this.m_coreV1.y); + var v1Y = xf.position.y + (tMat.col1.y * this.m_coreV1.x + tMat.col2.y * this.m_coreV1.y); + var v2X = xf.position.x + (tMat.col1.x * this.m_coreV2.x + tMat.col2.x * this.m_coreV2.y); + var v2Y = xf.position.y + (tMat.col1.y * this.m_coreV2.x + tMat.col2.y * this.m_coreV2.y); + if(v1X * dX + v1Y * dY > v2X * dX + v2Y * dY) { + this.s_supportVec.x = v1X; + this.s_supportVec.y = v1Y + }else { + this.s_supportVec.x = v2X; + this.s_supportVec.y = v2Y + } + return this.s_supportVec +}; +b2EdgeShape.prototype.s_supportVec = new b2Vec2; +b2EdgeShape.prototype.m_v1 = new b2Vec2; +b2EdgeShape.prototype.m_v2 = new b2Vec2; +b2EdgeShape.prototype.m_coreV1 = new b2Vec2; +b2EdgeShape.prototype.m_coreV2 = new b2Vec2; +b2EdgeShape.prototype.m_length = null; +b2EdgeShape.prototype.m_normal = new b2Vec2; +b2EdgeShape.prototype.m_direction = new b2Vec2; +b2EdgeShape.prototype.m_cornerDir1 = new b2Vec2; +b2EdgeShape.prototype.m_cornerDir2 = new b2Vec2; +b2EdgeShape.prototype.m_cornerConvex1 = null; +b2EdgeShape.prototype.m_cornerConvex2 = null; +b2EdgeShape.prototype.m_nextEdge = null; +b2EdgeShape.prototype.m_prevEdge = null;var b2BuoyancyController = function() { + b2Controller.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2BuoyancyController.prototype, b2Controller.prototype); +b2BuoyancyController.prototype._super = b2Controller.prototype; +b2BuoyancyController.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2BuoyancyController.prototype.__varz = function() { + this.normal = new b2Vec2(0, -1); + this.velocity = new b2Vec2(0, 0) +}; +b2BuoyancyController.prototype.Step = function(step) { + if(!m_bodyList) { + return + } + if(this.useWorldGravity) { + this.gravity = this.GetWorld().GetGravity().Copy() + } + for(var i = m_bodyList;i;i = i.nextBody) { + var body = i.body; + if(body.IsAwake() == false) { + continue + } + var areac = new b2Vec2; + var massc = new b2Vec2; + var area = 0; + var mass = 0; + for(var fixture = body.GetFixtureList();fixture;fixture = fixture.GetNext()) { + var sc = new b2Vec2; + var sarea = fixture.GetShape().ComputeSubmergedArea(this.normal, this.offset, body.GetTransform(), sc); + area += sarea; + areac.x += sarea * sc.x; + areac.y += sarea * sc.y; + var shapeDensity; + if(this.useDensity) { + shapeDensity = 1 + }else { + shapeDensity = 1 + } + mass += sarea * shapeDensity; + massc.x += sarea * sc.x * shapeDensity; + massc.y += sarea * sc.y * shapeDensity + } + areac.x /= area; + areac.y /= area; + massc.x /= mass; + massc.y /= mass; + if(area < Number.MIN_VALUE) { + continue + } + var buoyancyForce = this.gravity.GetNegative(); + buoyancyForce.Multiply(this.density * area); + body.ApplyForce(buoyancyForce, massc); + var dragForce = body.GetLinearVelocityFromWorldPoint(areac); + dragForce.Subtract(this.velocity); + dragForce.Multiply(-this.linearDrag * area); + body.ApplyForce(dragForce, areac); + body.ApplyTorque(-body.GetInertia() / body.GetMass() * area * body.GetAngularVelocity() * this.angularDrag) + } +}; +b2BuoyancyController.prototype.Draw = function(debugDraw) { + var r = 1E3; + var p1 = new b2Vec2; + var p2 = new b2Vec2; + p1.x = this.normal.x * this.offset + this.normal.y * r; + p1.y = this.normal.y * this.offset - this.normal.x * r; + p2.x = this.normal.x * this.offset - this.normal.y * r; + p2.y = this.normal.y * this.offset + this.normal.x * r; + var color = new b2Color(0, 0, 1); + debugDraw.DrawSegment(p1, p2, color) +}; +b2BuoyancyController.prototype.normal = new b2Vec2(0, -1); +b2BuoyancyController.prototype.offset = 0; +b2BuoyancyController.prototype.density = 0; +b2BuoyancyController.prototype.velocity = new b2Vec2(0, 0); +b2BuoyancyController.prototype.linearDrag = 2; +b2BuoyancyController.prototype.angularDrag = 1; +b2BuoyancyController.prototype.useDensity = false; +b2BuoyancyController.prototype.useWorldGravity = true; +b2BuoyancyController.prototype.gravity = null;var b2Body = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Body.prototype.__constructor = function(bd, world) { + this.m_flags = 0; + if(bd.bullet) { + this.m_flags |= b2Body.e_bulletFlag + } + if(bd.fixedRotation) { + this.m_flags |= b2Body.e_fixedRotationFlag + } + if(bd.allowSleep) { + this.m_flags |= b2Body.e_allowSleepFlag + } + if(bd.awake) { + this.m_flags |= b2Body.e_awakeFlag + } + if(bd.active) { + this.m_flags |= b2Body.e_activeFlag + } + this.m_world = world; + this.m_xf.position.SetV(bd.position); + this.m_xf.R.Set(bd.angle); + this.m_sweep.localCenter.SetZero(); + this.m_sweep.t0 = 1; + this.m_sweep.a0 = this.m_sweep.a = bd.angle; + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_sweep.c.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + this.m_sweep.c.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + this.m_sweep.c0.SetV(this.m_sweep.c); + this.m_jointList = null; + this.m_controllerList = null; + this.m_contactList = null; + this.m_controllerCount = 0; + this.m_prev = null; + this.m_next = null; + this.m_linearVelocity.SetV(bd.linearVelocity); + this.m_angularVelocity = bd.angularVelocity; + this.m_linearDamping = bd.linearDamping; + this.m_angularDamping = bd.angularDamping; + this.m_force.Set(0, 0); + this.m_torque = 0; + this.m_sleepTime = 0; + this.m_type = bd.type; + if(this.m_type == b2Body.b2_dynamicBody) { + this.m_mass = 1; + this.m_invMass = 1 + }else { + this.m_mass = 0; + this.m_invMass = 0 + } + this.m_I = 0; + this.m_invI = 0; + this.m_inertiaScale = bd.inertiaScale; + this.m_userData = bd.userData; + this.m_fixtureList = null; + this.m_fixtureCount = 0 +}; +b2Body.prototype.__varz = function() { + this.m_xf = new b2Transform; + this.m_sweep = new b2Sweep; + this.m_linearVelocity = new b2Vec2; + this.m_force = new b2Vec2 +}; +b2Body.b2_staticBody = 0; +b2Body.b2_kinematicBody = 1; +b2Body.b2_dynamicBody = 2; +b2Body.s_xf1 = new b2Transform; +b2Body.e_islandFlag = 1; +b2Body.e_awakeFlag = 2; +b2Body.e_allowSleepFlag = 4; +b2Body.e_bulletFlag = 8; +b2Body.e_fixedRotationFlag = 16; +b2Body.e_activeFlag = 32; +b2Body.prototype.connectEdges = function(s1, s2, angle1) { + var angle2 = Math.atan2(s2.GetDirectionVector().y, s2.GetDirectionVector().x); + var coreOffset = Math.tan((angle2 - angle1) * 0.5); + var core = b2Math.MulFV(coreOffset, s2.GetDirectionVector()); + core = b2Math.SubtractVV(core, s2.GetNormalVector()); + core = b2Math.MulFV(b2Settings.b2_toiSlop, core); + core = b2Math.AddVV(core, s2.GetVertex1()); + var cornerDir = b2Math.AddVV(s1.GetDirectionVector(), s2.GetDirectionVector()); + cornerDir.Normalize(); + var convex = b2Math.Dot(s1.GetDirectionVector(), s2.GetNormalVector()) > 0; + s1.SetNextEdge(s2, core, cornerDir, convex); + s2.SetPrevEdge(s1, core, cornerDir, convex); + return angle2 +}; +b2Body.prototype.SynchronizeFixtures = function() { + var xf1 = b2Body.s_xf1; + xf1.R.Set(this.m_sweep.a0); + var tMat = xf1.R; + var tVec = this.m_sweep.localCenter; + xf1.position.x = this.m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + xf1.position.y = this.m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var f; + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + for(f = this.m_fixtureList;f;f = f.m_next) { + f.Synchronize(broadPhase, xf1, this.m_xf) + } +}; +b2Body.prototype.SynchronizeTransform = function() { + this.m_xf.R.Set(this.m_sweep.a); + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_xf.position.x = this.m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + this.m_xf.position.y = this.m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y) +}; +b2Body.prototype.ShouldCollide = function(other) { + if(this.m_type != b2Body.b2_dynamicBody && other.m_type != b2Body.b2_dynamicBody) { + return false + } + for(var jn = this.m_jointList;jn;jn = jn.next) { + if(jn.other == other) { + if(jn.joint.m_collideConnected == false) { + return false + } + } + } + return true +}; +b2Body.prototype.Advance = function(t) { + this.m_sweep.Advance(t); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_sweep.a = this.m_sweep.a0; + this.SynchronizeTransform() +}; +b2Body.prototype.CreateFixture = function(def) { + if(this.m_world.IsLocked() == true) { + return null + } + var fixture = new b2Fixture; + fixture.Create(this, this.m_xf, def); + if(this.m_flags & b2Body.e_activeFlag) { + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + fixture.CreateProxy(broadPhase, this.m_xf) + } + fixture.m_next = this.m_fixtureList; + this.m_fixtureList = fixture; + ++this.m_fixtureCount; + fixture.m_body = this; + if(fixture.m_density > 0) { + this.ResetMassData() + } + this.m_world.m_flags |= b2World.e_newFixture; + return fixture +}; +b2Body.prototype.CreateFixture2 = function(shape, density) { + var def = new b2FixtureDef; + def.shape = shape; + def.density = density; + return this.CreateFixture(def) +}; +b2Body.prototype.DestroyFixture = function(fixture) { + if(this.m_world.IsLocked() == true) { + return + } + var node = this.m_fixtureList; + var ppF = null; + var found = false; + while(node != null) { + if(node == fixture) { + if(ppF) { + ppF.m_next = fixture.m_next + }else { + this.m_fixtureList = fixture.m_next + } + found = true; + break + } + ppF = node; + node = node.m_next + } + var edge = this.m_contactList; + while(edge) { + var c = edge.contact; + edge = edge.next; + var fixtureA = c.GetFixtureA(); + var fixtureB = c.GetFixtureB(); + if(fixture == fixtureA || fixture == fixtureB) { + this.m_world.m_contactManager.Destroy(c) + } + } + if(this.m_flags & b2Body.e_activeFlag) { + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + fixture.DestroyProxy(broadPhase) + }else { + } + fixture.Destroy(); + fixture.m_body = null; + fixture.m_next = null; + --this.m_fixtureCount; + this.ResetMassData() +}; +b2Body.prototype.SetPositionAndAngle = function(position, angle) { + var f; + if(this.m_world.IsLocked() == true) { + return + } + this.m_xf.R.Set(angle); + this.m_xf.position.SetV(position); + var tMat = this.m_xf.R; + var tVec = this.m_sweep.localCenter; + this.m_sweep.c.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + this.m_sweep.c.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + this.m_sweep.c.x += this.m_xf.position.x; + this.m_sweep.c.y += this.m_xf.position.y; + this.m_sweep.c0.SetV(this.m_sweep.c); + this.m_sweep.a0 = this.m_sweep.a = angle; + var broadPhase = this.m_world.m_contactManager.m_broadPhase; + for(f = this.m_fixtureList;f;f = f.m_next) { + f.Synchronize(broadPhase, this.m_xf, this.m_xf) + } + this.m_world.m_contactManager.FindNewContacts() +}; +b2Body.prototype.SetTransform = function(xf) { + this.SetPositionAndAngle(xf.position, xf.GetAngle()) +}; +b2Body.prototype.GetTransform = function() { + return this.m_xf +}; +b2Body.prototype.GetPosition = function() { + return this.m_xf.position +}; +b2Body.prototype.SetPosition = function(position) { + this.SetPositionAndAngle(position, this.GetAngle()) +}; +b2Body.prototype.GetAngle = function() { + return this.m_sweep.a +}; +b2Body.prototype.SetAngle = function(angle) { + this.SetPositionAndAngle(this.GetPosition(), angle) +}; +b2Body.prototype.GetWorldCenter = function() { + return this.m_sweep.c +}; +b2Body.prototype.GetLocalCenter = function() { + return this.m_sweep.localCenter +}; +b2Body.prototype.SetLinearVelocity = function(v) { + if(this.m_type == b2Body.b2_staticBody) { + return + } + this.m_linearVelocity.SetV(v) +}; +b2Body.prototype.GetLinearVelocity = function() { + return this.m_linearVelocity +}; +b2Body.prototype.SetAngularVelocity = function(omega) { + if(this.m_type == b2Body.b2_staticBody) { + return + } + this.m_angularVelocity = omega +}; +b2Body.prototype.GetAngularVelocity = function() { + return this.m_angularVelocity +}; +b2Body.prototype.GetDefinition = function() { + var bd = new b2BodyDef; + bd.type = this.GetType(); + bd.allowSleep = (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; + bd.angle = this.GetAngle(); + bd.angularDamping = this.m_angularDamping; + bd.angularVelocity = this.m_angularVelocity; + bd.fixedRotation = (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; + bd.bullet = (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; + bd.awake = (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; + bd.linearDamping = this.m_linearDamping; + bd.linearVelocity.SetV(this.GetLinearVelocity()); + bd.position = this.GetPosition(); + bd.userData = this.GetUserData(); + return bd +}; +b2Body.prototype.ApplyForce = function(force, point) { + if(this.m_type != b2Body.b2_dynamicBody) { + return + } + if(this.IsAwake() == false) { + this.SetAwake(true) + } + this.m_force.x += force.x; + this.m_force.y += force.y; + this.m_torque += (point.x - this.m_sweep.c.x) * force.y - (point.y - this.m_sweep.c.y) * force.x +}; +b2Body.prototype.ApplyTorque = function(torque) { + if(this.m_type != b2Body.b2_dynamicBody) { + return + } + if(this.IsAwake() == false) { + this.SetAwake(true) + } + this.m_torque += torque +}; +b2Body.prototype.ApplyImpulse = function(impulse, point) { + if(this.m_type != b2Body.b2_dynamicBody) { + return + } + if(this.IsAwake() == false) { + this.SetAwake(true) + } + this.m_linearVelocity.x += this.m_invMass * impulse.x; + this.m_linearVelocity.y += this.m_invMass * impulse.y; + this.m_angularVelocity += this.m_invI * ((point.x - this.m_sweep.c.x) * impulse.y - (point.y - this.m_sweep.c.y) * impulse.x) +}; +b2Body.prototype.Split = function(callback) { + var linearVelocity = this.GetLinearVelocity().Copy(); + var angularVelocity = this.GetAngularVelocity(); + var center = this.GetWorldCenter(); + var body1 = this; + var body2 = this.m_world.CreateBody(this.GetDefinition()); + var prev; + for(var f = body1.m_fixtureList;f;) { + if(callback(f)) { + var next = f.m_next; + if(prev) { + prev.m_next = next + }else { + body1.m_fixtureList = next + } + body1.m_fixtureCount--; + f.m_next = body2.m_fixtureList; + body2.m_fixtureList = f; + body2.m_fixtureCount++; + f.m_body = body2; + f = next + }else { + prev = f; + f = f.m_next + } + } + body1.ResetMassData(); + body2.ResetMassData(); + var center1 = body1.GetWorldCenter(); + var center2 = body2.GetWorldCenter(); + var velocity1 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center1, center))); + var velocity2 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center2, center))); + body1.SetLinearVelocity(velocity1); + body2.SetLinearVelocity(velocity2); + body1.SetAngularVelocity(angularVelocity); + body2.SetAngularVelocity(angularVelocity); + body1.SynchronizeFixtures(); + body2.SynchronizeFixtures(); + return body2 +}; +b2Body.prototype.Merge = function(other) { + var f; + for(f = other.m_fixtureList;f;) { + var next = f.m_next; + other.m_fixtureCount--; + f.m_next = this.m_fixtureList; + this.m_fixtureList = f; + this.m_fixtureCount++; + f.m_body = body2; + f = next + } + body1.m_fixtureCount = 0; + var body1 = this; + var body2 = other; + var center1 = body1.GetWorldCenter(); + var center2 = body2.GetWorldCenter(); + var velocity1 = body1.GetLinearVelocity().Copy(); + var velocity2 = body2.GetLinearVelocity().Copy(); + var angular1 = body1.GetAngularVelocity(); + var angular = body2.GetAngularVelocity(); + body1.ResetMassData(); + this.SynchronizeFixtures() +}; +b2Body.prototype.GetMass = function() { + return this.m_mass +}; +b2Body.prototype.GetInertia = function() { + return this.m_I +}; +b2Body.prototype.GetMassData = function(data) { + data.mass = this.m_mass; + data.I = this.m_I; + data.center.SetV(this.m_sweep.localCenter) +}; +b2Body.prototype.SetMassData = function(massData) { + b2Settings.b2Assert(this.m_world.IsLocked() == false); + if(this.m_world.IsLocked() == true) { + return + } + if(this.m_type != b2Body.b2_dynamicBody) { + return + } + this.m_invMass = 0; + this.m_I = 0; + this.m_invI = 0; + this.m_mass = massData.mass; + if(this.m_mass <= 0) { + this.m_mass = 1 + } + this.m_invMass = 1 / this.m_mass; + if(massData.I > 0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { + this.m_I = massData.I - this.m_mass * (massData.center.x * massData.center.x + massData.center.y * massData.center.y); + this.m_invI = 1 / this.m_I + } + var oldCenter = this.m_sweep.c.Copy(); + this.m_sweep.localCenter.SetV(massData.center); + this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_linearVelocity.x += this.m_angularVelocity * -(this.m_sweep.c.y - oldCenter.y); + this.m_linearVelocity.y += this.m_angularVelocity * +(this.m_sweep.c.x - oldCenter.x) +}; +b2Body.prototype.ResetMassData = function() { + this.m_mass = 0; + this.m_invMass = 0; + this.m_I = 0; + this.m_invI = 0; + this.m_sweep.localCenter.SetZero(); + if(this.m_type == b2Body.b2_staticBody || this.m_type == b2Body.b2_kinematicBody) { + return + } + var center = b2Vec2.Make(0, 0); + for(var f = this.m_fixtureList;f;f = f.m_next) { + if(f.m_density == 0) { + continue + } + var massData = f.GetMassData(); + this.m_mass += massData.mass; + center.x += massData.center.x * massData.mass; + center.y += massData.center.y * massData.mass; + this.m_I += massData.I + } + if(this.m_mass > 0) { + this.m_invMass = 1 / this.m_mass; + center.x *= this.m_invMass; + center.y *= this.m_invMass + }else { + this.m_mass = 1; + this.m_invMass = 1 + } + if(this.m_I > 0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { + this.m_I -= this.m_mass * (center.x * center.x + center.y * center.y); + this.m_I *= this.m_inertiaScale; + b2Settings.b2Assert(this.m_I > 0); + this.m_invI = 1 / this.m_I + }else { + this.m_I = 0; + this.m_invI = 0 + } + var oldCenter = this.m_sweep.c.Copy(); + this.m_sweep.localCenter.SetV(center); + this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); + this.m_sweep.c.SetV(this.m_sweep.c0); + this.m_linearVelocity.x += this.m_angularVelocity * -(this.m_sweep.c.y - oldCenter.y); + this.m_linearVelocity.y += this.m_angularVelocity * +(this.m_sweep.c.x - oldCenter.x) +}; +b2Body.prototype.GetWorldPoint = function(localPoint) { + var A = this.m_xf.R; + var u = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); + u.x += this.m_xf.position.x; + u.y += this.m_xf.position.y; + return u +}; +b2Body.prototype.GetWorldVector = function(localVector) { + return b2Math.MulMV(this.m_xf.R, localVector) +}; +b2Body.prototype.GetLocalPoint = function(worldPoint) { + return b2Math.MulXT(this.m_xf, worldPoint) +}; +b2Body.prototype.GetLocalVector = function(worldVector) { + return b2Math.MulTMV(this.m_xf.R, worldVector) +}; +b2Body.prototype.GetLinearVelocityFromWorldPoint = function(worldPoint) { + return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)) +}; +b2Body.prototype.GetLinearVelocityFromLocalPoint = function(localPoint) { + var A = this.m_xf.R; + var worldPoint = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); + worldPoint.x += this.m_xf.position.x; + worldPoint.y += this.m_xf.position.y; + return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)) +}; +b2Body.prototype.GetLinearDamping = function() { + return this.m_linearDamping +}; +b2Body.prototype.SetLinearDamping = function(linearDamping) { + this.m_linearDamping = linearDamping +}; +b2Body.prototype.GetAngularDamping = function() { + return this.m_angularDamping +}; +b2Body.prototype.SetAngularDamping = function(angularDamping) { + this.m_angularDamping = angularDamping +}; +b2Body.prototype.SetType = function(type) { + if(this.m_type == type) { + return + } + this.m_type = type; + this.ResetMassData(); + if(this.m_type == b2Body.b2_staticBody) { + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0 + } + this.SetAwake(true); + this.m_force.SetZero(); + this.m_torque = 0; + for(var ce = this.m_contactList;ce;ce = ce.next) { + ce.contact.FlagForFiltering() + } +}; +b2Body.prototype.GetType = function() { + return this.m_type +}; +b2Body.prototype.SetBullet = function(flag) { + if(flag) { + this.m_flags |= b2Body.e_bulletFlag + }else { + this.m_flags &= ~b2Body.e_bulletFlag + } +}; +b2Body.prototype.IsBullet = function() { + return(this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag +}; +b2Body.prototype.SetSleepingAllowed = function(flag) { + if(flag) { + this.m_flags |= b2Body.e_allowSleepFlag + }else { + this.m_flags &= ~b2Body.e_allowSleepFlag; + this.SetAwake(true) + } +}; +b2Body.prototype.SetAwake = function(flag) { + if(flag) { + this.m_flags |= b2Body.e_awakeFlag; + this.m_sleepTime = 0 + }else { + this.m_flags &= ~b2Body.e_awakeFlag; + this.m_sleepTime = 0; + this.m_linearVelocity.SetZero(); + this.m_angularVelocity = 0; + this.m_force.SetZero(); + this.m_torque = 0 + } +}; +b2Body.prototype.IsAwake = function() { + return(this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag +}; +b2Body.prototype.SetFixedRotation = function(fixed) { + if(fixed) { + this.m_flags |= b2Body.e_fixedRotationFlag + }else { + this.m_flags &= ~b2Body.e_fixedRotationFlag + } + this.ResetMassData() +}; +b2Body.prototype.IsFixedRotation = function() { + return(this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag +}; +b2Body.prototype.SetActive = function(flag) { + if(flag == this.IsActive()) { + return + } + var broadPhase; + var f; + if(flag) { + this.m_flags |= b2Body.e_activeFlag; + broadPhase = this.m_world.m_contactManager.m_broadPhase; + for(f = this.m_fixtureList;f;f = f.m_next) { + f.CreateProxy(broadPhase, this.m_xf) + } + }else { + this.m_flags &= ~b2Body.e_activeFlag; + broadPhase = this.m_world.m_contactManager.m_broadPhase; + for(f = this.m_fixtureList;f;f = f.m_next) { + f.DestroyProxy(broadPhase) + } + var ce = this.m_contactList; + while(ce) { + var ce0 = ce; + ce = ce.next; + this.m_world.m_contactManager.Destroy(ce0.contact) + } + this.m_contactList = null + } +}; +b2Body.prototype.IsActive = function() { + return(this.m_flags & b2Body.e_activeFlag) == b2Body.e_activeFlag +}; +b2Body.prototype.IsSleepingAllowed = function() { + return(this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag +}; +b2Body.prototype.GetFixtureList = function() { + return this.m_fixtureList +}; +b2Body.prototype.GetJointList = function() { + return this.m_jointList +}; +b2Body.prototype.GetControllerList = function() { + return this.m_controllerList +}; +b2Body.prototype.GetContactList = function() { + return this.m_contactList +}; +b2Body.prototype.GetNext = function() { + return this.m_next +}; +b2Body.prototype.GetUserData = function() { + return this.m_userData +}; +b2Body.prototype.SetUserData = function(data) { + this.m_userData = data +}; +b2Body.prototype.GetWorld = function() { + return this.m_world +}; +b2Body.prototype.m_flags = 0; +b2Body.prototype.m_type = 0; +b2Body.prototype.m_islandIndex = 0; +b2Body.prototype.m_xf = new b2Transform; +b2Body.prototype.m_sweep = new b2Sweep; +b2Body.prototype.m_linearVelocity = new b2Vec2; +b2Body.prototype.m_angularVelocity = null; +b2Body.prototype.m_force = new b2Vec2; +b2Body.prototype.m_torque = null; +b2Body.prototype.m_world = null; +b2Body.prototype.m_prev = null; +b2Body.prototype.m_next = null; +b2Body.prototype.m_fixtureList = null; +b2Body.prototype.m_fixtureCount = 0; +b2Body.prototype.m_controllerList = null; +b2Body.prototype.m_controllerCount = 0; +b2Body.prototype.m_jointList = null; +b2Body.prototype.m_contactList = null; +b2Body.prototype.m_mass = null; +b2Body.prototype.m_invMass = null; +b2Body.prototype.m_I = null; +b2Body.prototype.m_invI = null; +b2Body.prototype.m_inertiaScale = null; +b2Body.prototype.m_linearDamping = null; +b2Body.prototype.m_angularDamping = null; +b2Body.prototype.m_sleepTime = null; +b2Body.prototype.m_userData = null;var b2ContactImpulse = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactImpulse.prototype.__constructor = function() { +}; +b2ContactImpulse.prototype.__varz = function() { + this.normalImpulses = new Array(b2Settings.b2_maxManifoldPoints); + this.tangentImpulses = new Array(b2Settings.b2_maxManifoldPoints) +}; +b2ContactImpulse.prototype.normalImpulses = new Array(b2Settings.b2_maxManifoldPoints); +b2ContactImpulse.prototype.tangentImpulses = new Array(b2Settings.b2_maxManifoldPoints);var b2TensorDampingController = function() { + b2Controller.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2TensorDampingController.prototype, b2Controller.prototype); +b2TensorDampingController.prototype._super = b2Controller.prototype; +b2TensorDampingController.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2TensorDampingController.prototype.__varz = function() { + this.T = new b2Mat22 +}; +b2TensorDampingController.prototype.SetAxisAligned = function(xDamping, yDamping) { + this.T.col1.x = -xDamping; + this.T.col1.y = 0; + this.T.col2.x = 0; + this.T.col2.y = -yDamping; + if(xDamping > 0 || yDamping > 0) { + this.maxTimestep = 1 / Math.max(xDamping, yDamping) + }else { + this.maxTimestep = 0 + } +}; +b2TensorDampingController.prototype.Step = function(step) { + var timestep = step.dt; + if(timestep <= Number.MIN_VALUE) { + return + } + if(timestep > this.maxTimestep && this.maxTimestep > 0) { + timestep = this.maxTimestep + } + for(var i = m_bodyList;i;i = i.nextBody) { + var body = i.body; + if(!body.IsAwake()) { + continue + } + var damping = body.GetWorldVector(b2Math.MulMV(this.T, body.GetLocalVector(body.GetLinearVelocity()))); + body.SetLinearVelocity(new b2Vec2(body.GetLinearVelocity().x + damping.x * timestep, body.GetLinearVelocity().y + damping.y * timestep)) + } +}; +b2TensorDampingController.prototype.T = new b2Mat22; +b2TensorDampingController.prototype.maxTimestep = 0;var b2ManifoldPoint = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ManifoldPoint.prototype.__constructor = function() { + this.Reset() +}; +b2ManifoldPoint.prototype.__varz = function() { + this.m_localPoint = new b2Vec2; + this.m_id = new b2ContactID +}; +b2ManifoldPoint.prototype.Reset = function() { + this.m_localPoint.SetZero(); + this.m_normalImpulse = 0; + this.m_tangentImpulse = 0; + this.m_id.key = 0 +}; +b2ManifoldPoint.prototype.Set = function(m) { + this.m_localPoint.SetV(m.m_localPoint); + this.m_normalImpulse = m.m_normalImpulse; + this.m_tangentImpulse = m.m_tangentImpulse; + this.m_id.Set(m.m_id) +}; +b2ManifoldPoint.prototype.m_localPoint = new b2Vec2; +b2ManifoldPoint.prototype.m_normalImpulse = null; +b2ManifoldPoint.prototype.m_tangentImpulse = null; +b2ManifoldPoint.prototype.m_id = new b2ContactID;var b2PolygonShape = function() { + b2Shape.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PolygonShape.prototype, b2Shape.prototype); +b2PolygonShape.prototype._super = b2Shape.prototype; +b2PolygonShape.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.m_type = b2Shape.e_polygonShape; + this.m_centroid = new b2Vec2; + this.m_vertices = new Array; + this.m_normals = new Array +}; +b2PolygonShape.prototype.__varz = function() { +}; +b2PolygonShape.AsArray = function(vertices, vertexCount) { + var polygonShape = new b2PolygonShape; + polygonShape.SetAsArray(vertices, vertexCount); + return polygonShape +}; +b2PolygonShape.AsVector = function(vertices, vertexCount) { + var polygonShape = new b2PolygonShape; + polygonShape.SetAsVector(vertices, vertexCount); + return polygonShape +}; +b2PolygonShape.AsBox = function(hx, hy) { + var polygonShape = new b2PolygonShape; + polygonShape.SetAsBox(hx, hy); + return polygonShape +}; +b2PolygonShape.AsOrientedBox = function(hx, hy, center, angle) { + var polygonShape = new b2PolygonShape; + polygonShape.SetAsOrientedBox(hx, hy, center, angle); + return polygonShape +}; +b2PolygonShape.AsEdge = function(v1, v2) { + var polygonShape = new b2PolygonShape; + polygonShape.SetAsEdge(v1, v2); + return polygonShape +}; +b2PolygonShape.ComputeCentroid = function(vs, count) { + var c = new b2Vec2; + var area = 0; + var p1X = 0; + var p1Y = 0; + var inv3 = 1 / 3; + for(var i = 0;i < count;++i) { + var p2 = vs[i]; + var p3 = i + 1 < count ? vs[parseInt(i + 1)] : vs[0]; + var e1X = p2.x - p1X; + var e1Y = p2.y - p1Y; + var e2X = p3.x - p1X; + var e2Y = p3.y - p1Y; + var D = e1X * e2Y - e1Y * e2X; + var triangleArea = 0.5 * D; + area += triangleArea; + c.x += triangleArea * inv3 * (p1X + p2.x + p3.x); + c.y += triangleArea * inv3 * (p1Y + p2.y + p3.y) + } + c.x *= 1 / area; + c.y *= 1 / area; + return c +}; +b2PolygonShape.ComputeOBB = function(obb, vs, count) { + var i = 0; + var p = new Array(count + 1); + for(i = 0;i < count;++i) { + p[i] = vs[i] + } + p[count] = p[0]; + var minArea = Number.MAX_VALUE; + for(i = 1;i <= count;++i) { + var root = p[parseInt(i - 1)]; + var uxX = p[i].x - root.x; + var uxY = p[i].y - root.y; + var length = Math.sqrt(uxX * uxX + uxY * uxY); + uxX /= length; + uxY /= length; + var uyX = -uxY; + var uyY = uxX; + var lowerX = Number.MAX_VALUE; + var lowerY = Number.MAX_VALUE; + var upperX = -Number.MAX_VALUE; + var upperY = -Number.MAX_VALUE; + for(var j = 0;j < count;++j) { + var dX = p[j].x - root.x; + var dY = p[j].y - root.y; + var rX = uxX * dX + uxY * dY; + var rY = uyX * dX + uyY * dY; + if(rX < lowerX) { + lowerX = rX + } + if(rY < lowerY) { + lowerY = rY + } + if(rX > upperX) { + upperX = rX + } + if(rY > upperY) { + upperY = rY + } + } + var area = (upperX - lowerX) * (upperY - lowerY); + if(area < 0.95 * minArea) { + minArea = area; + obb.R.col1.x = uxX; + obb.R.col1.y = uxY; + obb.R.col2.x = uyX; + obb.R.col2.y = uyY; + var centerX = 0.5 * (lowerX + upperX); + var centerY = 0.5 * (lowerY + upperY); + var tMat = obb.R; + obb.center.x = root.x + (tMat.col1.x * centerX + tMat.col2.x * centerY); + obb.center.y = root.y + (tMat.col1.y * centerX + tMat.col2.y * centerY); + obb.extents.x = 0.5 * (upperX - lowerX); + obb.extents.y = 0.5 * (upperY - lowerY) + } + } +}; +b2PolygonShape.s_mat = new b2Mat22; +b2PolygonShape.prototype.Validate = function() { + return false +}; +b2PolygonShape.prototype.Reserve = function(count) { + for(var i = this.m_vertices.length;i < count;i++) { + this.m_vertices[i] = new b2Vec2; + this.m_normals[i] = new b2Vec2 + } +}; +b2PolygonShape.prototype.Copy = function() { + var s = new b2PolygonShape; + s.Set(this); + return s +}; +b2PolygonShape.prototype.Set = function(other) { + this._super.Set.apply(this, [other]); + if(isInstanceOf(other, b2PolygonShape)) { + var other2 = other; + this.m_centroid.SetV(other2.m_centroid); + this.m_vertexCount = other2.m_vertexCount; + this.Reserve(this.m_vertexCount); + for(var i = 0;i < this.m_vertexCount;i++) { + this.m_vertices[i].SetV(other2.m_vertices[i]); + this.m_normals[i].SetV(other2.m_normals[i]) + } + } +}; +b2PolygonShape.prototype.SetAsArray = function(vertices, vertexCount) { + var v = new Array; + for(var i = 0, tVec = null;i < vertices.length, tVec = vertices[i];i++) { + v.push(tVec) + } + this.SetAsVector(v, vertexCount) +}; +b2PolygonShape.prototype.SetAsVector = function(vertices, vertexCount) { + if(typeof vertexCount == "undefined") { + vertexCount = vertices.length + } + b2Settings.b2Assert(2 <= vertexCount); + this.m_vertexCount = vertexCount; + this.Reserve(vertexCount); + var i = 0; + for(i = 0;i < this.m_vertexCount;i++) { + this.m_vertices[i].SetV(vertices[i]) + } + for(i = 0;i < this.m_vertexCount;++i) { + var i1 = i; + var i2 = i + 1 < this.m_vertexCount ? i + 1 : 0; + var edge = b2Math.SubtractVV(this.m_vertices[i2], this.m_vertices[i1]); + b2Settings.b2Assert(edge.LengthSquared() > Number.MIN_VALUE); + this.m_normals[i].SetV(b2Math.CrossVF(edge, 1)); + this.m_normals[i].Normalize() + } + this.m_centroid = b2PolygonShape.ComputeCentroid(this.m_vertices, this.m_vertexCount) +}; +b2PolygonShape.prototype.SetAsBox = function(hx, hy) { + this.m_vertexCount = 4; + this.Reserve(4); + this.m_vertices[0].Set(-hx, -hy); + this.m_vertices[1].Set(hx, -hy); + this.m_vertices[2].Set(hx, hy); + this.m_vertices[3].Set(-hx, hy); + this.m_normals[0].Set(0, -1); + this.m_normals[1].Set(1, 0); + this.m_normals[2].Set(0, 1); + this.m_normals[3].Set(-1, 0); + this.m_centroid.SetZero() +}; +b2PolygonShape.prototype.SetAsOrientedBox = function(hx, hy, center, angle) { + this.m_vertexCount = 4; + this.Reserve(4); + this.m_vertices[0].Set(-hx, -hy); + this.m_vertices[1].Set(hx, -hy); + this.m_vertices[2].Set(hx, hy); + this.m_vertices[3].Set(-hx, hy); + this.m_normals[0].Set(0, -1); + this.m_normals[1].Set(1, 0); + this.m_normals[2].Set(0, 1); + this.m_normals[3].Set(-1, 0); + this.m_centroid = center; + var xf = new b2Transform; + xf.position = center; + xf.R.Set(angle); + for(var i = 0;i < this.m_vertexCount;++i) { + this.m_vertices[i] = b2Math.MulX(xf, this.m_vertices[i]); + this.m_normals[i] = b2Math.MulMV(xf.R, this.m_normals[i]) + } +}; +b2PolygonShape.prototype.SetAsEdge = function(v1, v2) { + this.m_vertexCount = 2; + this.Reserve(2); + this.m_vertices[0].SetV(v1); + this.m_vertices[1].SetV(v2); + this.m_centroid.x = 0.5 * (v1.x + v2.x); + this.m_centroid.y = 0.5 * (v1.y + v2.y); + this.m_normals[0] = b2Math.CrossVF(b2Math.SubtractVV(v2, v1), 1); + this.m_normals[0].Normalize(); + this.m_normals[1].x = -this.m_normals[0].x; + this.m_normals[1].y = -this.m_normals[0].y +}; +b2PolygonShape.prototype.TestPoint = function(xf, p) { + var tVec; + var tMat = xf.R; + var tX = p.x - xf.position.x; + var tY = p.y - xf.position.y; + var pLocalX = tX * tMat.col1.x + tY * tMat.col1.y; + var pLocalY = tX * tMat.col2.x + tY * tMat.col2.y; + for(var i = 0;i < this.m_vertexCount;++i) { + tVec = this.m_vertices[i]; + tX = pLocalX - tVec.x; + tY = pLocalY - tVec.y; + tVec = this.m_normals[i]; + var dot = tVec.x * tX + tVec.y * tY; + if(dot > 0) { + return false + } + } + return true +}; +b2PolygonShape.prototype.RayCast = function(output, input, transform) { + var lower = 0; + var upper = input.maxFraction; + var tX; + var tY; + var tMat; + var tVec; + tX = input.p1.x - transform.position.x; + tY = input.p1.y - transform.position.y; + tMat = transform.R; + var p1X = tX * tMat.col1.x + tY * tMat.col1.y; + var p1Y = tX * tMat.col2.x + tY * tMat.col2.y; + tX = input.p2.x - transform.position.x; + tY = input.p2.y - transform.position.y; + tMat = transform.R; + var p2X = tX * tMat.col1.x + tY * tMat.col1.y; + var p2Y = tX * tMat.col2.x + tY * tMat.col2.y; + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var index = -1; + for(var i = 0;i < this.m_vertexCount;++i) { + tVec = this.m_vertices[i]; + tX = tVec.x - p1X; + tY = tVec.y - p1Y; + tVec = this.m_normals[i]; + var numerator = tVec.x * tX + tVec.y * tY; + var denominator = tVec.x * dX + tVec.y * dY; + if(denominator == 0) { + if(numerator < 0) { + return false + } + }else { + if(denominator < 0 && numerator < lower * denominator) { + lower = numerator / denominator; + index = i + }else { + if(denominator > 0 && numerator < upper * denominator) { + upper = numerator / denominator + } + } + } + if(upper < lower - Number.MIN_VALUE) { + return false + } + } + if(index >= 0) { + output.fraction = lower; + tMat = transform.R; + tVec = this.m_normals[index]; + output.normal.x = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + output.normal.y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + return true + } + return false +}; +b2PolygonShape.prototype.ComputeAABB = function(aabb, xf) { + var tMat = xf.R; + var tVec = this.m_vertices[0]; + var lowerX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var lowerY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var upperX = lowerX; + var upperY = lowerY; + for(var i = 1;i < this.m_vertexCount;++i) { + tVec = this.m_vertices[i]; + var vX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var vY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + lowerX = lowerX < vX ? lowerX : vX; + lowerY = lowerY < vY ? lowerY : vY; + upperX = upperX > vX ? upperX : vX; + upperY = upperY > vY ? upperY : vY + } + aabb.lowerBound.x = lowerX - this.m_radius; + aabb.lowerBound.y = lowerY - this.m_radius; + aabb.upperBound.x = upperX + this.m_radius; + aabb.upperBound.y = upperY + this.m_radius +}; +b2PolygonShape.prototype.ComputeMass = function(massData, density) { + if(this.m_vertexCount == 2) { + massData.center.x = 0.5 * (this.m_vertices[0].x + this.m_vertices[1].x); + massData.center.y = 0.5 * (this.m_vertices[0].y + this.m_vertices[1].y); + massData.mass = 0; + massData.I = 0; + return + } + var centerX = 0; + var centerY = 0; + var area = 0; + var I = 0; + var p1X = 0; + var p1Y = 0; + var k_inv3 = 1 / 3; + for(var i = 0;i < this.m_vertexCount;++i) { + var p2 = this.m_vertices[i]; + var p3 = i + 1 < this.m_vertexCount ? this.m_vertices[parseInt(i + 1)] : this.m_vertices[0]; + var e1X = p2.x - p1X; + var e1Y = p2.y - p1Y; + var e2X = p3.x - p1X; + var e2Y = p3.y - p1Y; + var D = e1X * e2Y - e1Y * e2X; + var triangleArea = 0.5 * D; + area += triangleArea; + centerX += triangleArea * k_inv3 * (p1X + p2.x + p3.x); + centerY += triangleArea * k_inv3 * (p1Y + p2.y + p3.y); + var px = p1X; + var py = p1Y; + var ex1 = e1X; + var ey1 = e1Y; + var ex2 = e2X; + var ey2 = e2Y; + var intx2 = k_inv3 * (0.25 * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5 * px * px; + var inty2 = k_inv3 * (0.25 * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5 * py * py; + I += D * (intx2 + inty2) + } + massData.mass = density * area; + centerX *= 1 / area; + centerY *= 1 / area; + massData.center.Set(centerX, centerY); + massData.I = density * I +}; +b2PolygonShape.prototype.ComputeSubmergedArea = function(normal, offset, xf, c) { + var normalL = b2Math.MulTMV(xf.R, normal); + var offsetL = offset - b2Math.Dot(normal, xf.position); + var depths = new Array; + var diveCount = 0; + var intoIndex = -1; + var outoIndex = -1; + var lastSubmerged = false; + var i = 0; + for(i = 0;i < this.m_vertexCount;++i) { + depths[i] = b2Math.Dot(normalL, this.m_vertices[i]) - offsetL; + var isSubmerged = depths[i] < -Number.MIN_VALUE; + if(i > 0) { + if(isSubmerged) { + if(!lastSubmerged) { + intoIndex = i - 1; + diveCount++ + } + }else { + if(lastSubmerged) { + outoIndex = i - 1; + diveCount++ + } + } + } + lastSubmerged = isSubmerged + } + switch(diveCount) { + case 0: + if(lastSubmerged) { + var md = new b2MassData; + this.ComputeMass(md, 1); + c.SetV(b2Math.MulX(xf, md.center)); + return md.mass + }else { + return 0 + } + break; + case 1: + if(intoIndex == -1) { + intoIndex = this.m_vertexCount - 1 + }else { + outoIndex = this.m_vertexCount - 1 + } + break + } + var intoIndex2 = (intoIndex + 1) % this.m_vertexCount; + var outoIndex2 = (outoIndex + 1) % this.m_vertexCount; + var intoLamdda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]); + var outoLamdda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]); + var intoVec = new b2Vec2(this.m_vertices[intoIndex].x * (1 - intoLamdda) + this.m_vertices[intoIndex2].x * intoLamdda, this.m_vertices[intoIndex].y * (1 - intoLamdda) + this.m_vertices[intoIndex2].y * intoLamdda); + var outoVec = new b2Vec2(this.m_vertices[outoIndex].x * (1 - outoLamdda) + this.m_vertices[outoIndex2].x * outoLamdda, this.m_vertices[outoIndex].y * (1 - outoLamdda) + this.m_vertices[outoIndex2].y * outoLamdda); + var area = 0; + var center = new b2Vec2; + var p2 = this.m_vertices[intoIndex2]; + var p3; + i = intoIndex2; + while(i != outoIndex2) { + i = (i + 1) % this.m_vertexCount; + if(i == outoIndex2) { + p3 = outoVec + }else { + p3 = this.m_vertices[i] + } + var triangleArea = 0.5 * ((p2.x - intoVec.x) * (p3.y - intoVec.y) - (p2.y - intoVec.y) * (p3.x - intoVec.x)); + area += triangleArea; + center.x += triangleArea * (intoVec.x + p2.x + p3.x) / 3; + center.y += triangleArea * (intoVec.y + p2.y + p3.y) / 3; + p2 = p3 + } + center.Multiply(1 / area); + c.SetV(b2Math.MulX(xf, center)); + return area +}; +b2PolygonShape.prototype.GetVertexCount = function() { + return this.m_vertexCount +}; +b2PolygonShape.prototype.GetVertices = function() { + return this.m_vertices +}; +b2PolygonShape.prototype.GetNormals = function() { + return this.m_normals +}; +b2PolygonShape.prototype.GetSupport = function(d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for(var i = 1;i < this.m_vertexCount;++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if(value > bestValue) { + bestIndex = i; + bestValue = value + } + } + return bestIndex +}; +b2PolygonShape.prototype.GetSupportVertex = function(d) { + var bestIndex = 0; + var bestValue = this.m_vertices[0].x * d.x + this.m_vertices[0].y * d.y; + for(var i = 1;i < this.m_vertexCount;++i) { + var value = this.m_vertices[i].x * d.x + this.m_vertices[i].y * d.y; + if(value > bestValue) { + bestIndex = i; + bestValue = value + } + } + return this.m_vertices[bestIndex] +}; +b2PolygonShape.prototype.m_centroid = null; +b2PolygonShape.prototype.m_vertices = null; +b2PolygonShape.prototype.m_normals = null; +b2PolygonShape.prototype.m_vertexCount = 0;var b2Fixture = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Fixture.prototype.__constructor = function() { + this.m_aabb = new b2AABB; + this.m_userData = null; + this.m_body = null; + this.m_next = null; + this.m_shape = null; + this.m_density = 0; + this.m_friction = 0; + this.m_restitution = 0 +}; +b2Fixture.prototype.__varz = function() { + this.m_filter = new b2FilterData +}; +b2Fixture.prototype.Create = function(body, xf, def) { + this.m_userData = def.userData; + this.m_friction = def.friction; + this.m_restitution = def.restitution; + this.m_body = body; + this.m_next = null; + this.m_filter = def.filter.Copy(); + this.m_isSensor = def.isSensor; + this.m_shape = def.shape.Copy(); + this.m_density = def.density +}; +b2Fixture.prototype.Destroy = function() { + this.m_shape = null +}; +b2Fixture.prototype.CreateProxy = function(broadPhase, xf) { + this.m_shape.ComputeAABB(this.m_aabb, xf); + this.m_proxy = broadPhase.CreateProxy(this.m_aabb, this) +}; +b2Fixture.prototype.DestroyProxy = function(broadPhase) { + if(this.m_proxy == null) { + return + } + broadPhase.DestroyProxy(this.m_proxy); + this.m_proxy = null +}; +b2Fixture.prototype.Synchronize = function(broadPhase, transform1, transform2) { + if(!this.m_proxy) { + return + } + var aabb1 = new b2AABB; + var aabb2 = new b2AABB; + this.m_shape.ComputeAABB(aabb1, transform1); + this.m_shape.ComputeAABB(aabb2, transform2); + this.m_aabb.Combine(aabb1, aabb2); + var displacement = b2Math.SubtractVV(transform2.position, transform1.position); + broadPhase.MoveProxy(this.m_proxy, this.m_aabb, displacement) +}; +b2Fixture.prototype.GetType = function() { + return this.m_shape.GetType() +}; +b2Fixture.prototype.GetShape = function() { + return this.m_shape +}; +b2Fixture.prototype.SetSensor = function(sensor) { + if(this.m_isSensor == sensor) { + return + } + this.m_isSensor = sensor; + if(this.m_body == null) { + return + } + var edge = this.m_body.GetContactList(); + while(edge) { + var contact = edge.contact; + var fixtureA = contact.GetFixtureA(); + var fixtureB = contact.GetFixtureB(); + if(fixtureA == this || fixtureB == this) { + contact.SetSensor(fixtureA.IsSensor() || fixtureB.IsSensor()) + } + edge = edge.next + } +}; +b2Fixture.prototype.IsSensor = function() { + return this.m_isSensor +}; +b2Fixture.prototype.SetFilterData = function(filter) { + this.m_filter = filter.Copy(); + if(this.m_body) { + return + } + var edge = this.m_body.GetContactList(); + while(edge) { + var contact = edge.contact; + var fixtureA = contact.GetFixtureA(); + var fixtureB = contact.GetFixtureB(); + if(fixtureA == this || fixtureB == this) { + contact.FlagForFiltering() + } + edge = edge.next + } +}; +b2Fixture.prototype.GetFilterData = function() { + return this.m_filter.Copy() +}; +b2Fixture.prototype.GetBody = function() { + return this.m_body +}; +b2Fixture.prototype.GetNext = function() { + return this.m_next +}; +b2Fixture.prototype.GetUserData = function() { + return this.m_userData +}; +b2Fixture.prototype.SetUserData = function(data) { + this.m_userData = data +}; +b2Fixture.prototype.TestPoint = function(p) { + return this.m_shape.TestPoint(this.m_body.GetTransform(), p) +}; +b2Fixture.prototype.RayCast = function(output, input) { + return this.m_shape.RayCast(output, input, this.m_body.GetTransform()) +}; +b2Fixture.prototype.GetMassData = function(massData) { + if(massData == null) { + massData = new b2MassData + } + this.m_shape.ComputeMass(massData, this.m_density); + return massData +}; +b2Fixture.prototype.SetDensity = function(density) { + this.m_density = density +}; +b2Fixture.prototype.GetDensity = function() { + return this.m_density +}; +b2Fixture.prototype.GetFriction = function() { + return this.m_friction +}; +b2Fixture.prototype.SetFriction = function(friction) { + this.m_friction = friction +}; +b2Fixture.prototype.GetRestitution = function() { + return this.m_restitution +}; +b2Fixture.prototype.SetRestitution = function(restitution) { + this.m_restitution = restitution +}; +b2Fixture.prototype.GetAABB = function() { + return this.m_aabb +}; +b2Fixture.prototype.m_massData = null; +b2Fixture.prototype.m_aabb = null; +b2Fixture.prototype.m_density = null; +b2Fixture.prototype.m_next = null; +b2Fixture.prototype.m_body = null; +b2Fixture.prototype.m_shape = null; +b2Fixture.prototype.m_friction = null; +b2Fixture.prototype.m_restitution = null; +b2Fixture.prototype.m_proxy = null; +b2Fixture.prototype.m_filter = new b2FilterData; +b2Fixture.prototype.m_isSensor = null; +b2Fixture.prototype.m_userData = null;var b2DynamicTreeNode = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DynamicTreeNode.prototype.__constructor = function() { +}; +b2DynamicTreeNode.prototype.__varz = function() { + this.aabb = new b2AABB +}; +b2DynamicTreeNode.prototype.IsLeaf = function() { + return this.child1 == null +}; +b2DynamicTreeNode.prototype.userData = null; +b2DynamicTreeNode.prototype.aabb = new b2AABB; +b2DynamicTreeNode.prototype.parent = null; +b2DynamicTreeNode.prototype.child1 = null; +b2DynamicTreeNode.prototype.child2 = null;var b2BodyDef = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2BodyDef.prototype.__constructor = function() { + this.userData = null; + this.position.Set(0, 0); + this.angle = 0; + this.linearVelocity.Set(0, 0); + this.angularVelocity = 0; + this.linearDamping = 0; + this.angularDamping = 0; + this.allowSleep = true; + this.awake = true; + this.fixedRotation = false; + this.bullet = false; + this.type = b2Body.b2_staticBody; + this.active = true; + this.inertiaScale = 1 +}; +b2BodyDef.prototype.__varz = function() { + this.position = new b2Vec2; + this.linearVelocity = new b2Vec2 +}; +b2BodyDef.prototype.type = 0; +b2BodyDef.prototype.position = new b2Vec2; +b2BodyDef.prototype.angle = null; +b2BodyDef.prototype.linearVelocity = new b2Vec2; +b2BodyDef.prototype.angularVelocity = null; +b2BodyDef.prototype.linearDamping = null; +b2BodyDef.prototype.angularDamping = null; +b2BodyDef.prototype.allowSleep = null; +b2BodyDef.prototype.awake = null; +b2BodyDef.prototype.fixedRotation = null; +b2BodyDef.prototype.bullet = null; +b2BodyDef.prototype.active = null; +b2BodyDef.prototype.userData = null; +b2BodyDef.prototype.inertiaScale = null;var b2DynamicTreeBroadPhase = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2DynamicTreeBroadPhase.prototype.__constructor = function() { +}; +b2DynamicTreeBroadPhase.prototype.__varz = function() { + this.m_tree = new b2DynamicTree; + this.m_moveBuffer = new Array; + this.m_pairBuffer = new Array +}; +b2DynamicTreeBroadPhase.prototype.BufferMove = function(proxy) { + this.m_moveBuffer[this.m_moveBuffer.length] = proxy +}; +b2DynamicTreeBroadPhase.prototype.UnBufferMove = function(proxy) { + var i = this.m_moveBuffer.indexOf(proxy); + this.m_moveBuffer.splice(i, 1) +}; +b2DynamicTreeBroadPhase.prototype.ComparePairs = function(pair1, pair2) { + return 0 +}; +b2DynamicTreeBroadPhase.prototype.CreateProxy = function(aabb, userData) { + var proxy = this.m_tree.CreateProxy(aabb, userData); + ++this.m_proxyCount; + this.BufferMove(proxy); + return proxy +}; +b2DynamicTreeBroadPhase.prototype.DestroyProxy = function(proxy) { + this.UnBufferMove(proxy); + --this.m_proxyCount; + this.m_tree.DestroyProxy(proxy) +}; +b2DynamicTreeBroadPhase.prototype.MoveProxy = function(proxy, aabb, displacement) { + var buffer = this.m_tree.MoveProxy(proxy, aabb, displacement); + if(buffer) { + this.BufferMove(proxy) + } +}; +b2DynamicTreeBroadPhase.prototype.TestOverlap = function(proxyA, proxyB) { + var aabbA = this.m_tree.GetFatAABB(proxyA); + var aabbB = this.m_tree.GetFatAABB(proxyB); + return aabbA.TestOverlap(aabbB) +}; +b2DynamicTreeBroadPhase.prototype.GetUserData = function(proxy) { + return this.m_tree.GetUserData(proxy) +}; +b2DynamicTreeBroadPhase.prototype.GetFatAABB = function(proxy) { + return this.m_tree.GetFatAABB(proxy) +}; +b2DynamicTreeBroadPhase.prototype.GetProxyCount = function() { + return this.m_proxyCount +}; +b2DynamicTreeBroadPhase.prototype.UpdatePairs = function(callback) { + this.m_pairCount = 0; + for(var i = 0, queryProxy = null;i < this.m_moveBuffer.length, queryProxy = this.m_moveBuffer[i];i++) { + var that = this; + function QueryCallback(proxy) { + if(proxy == queryProxy) { + return true + } + if(that.m_pairCount == that.m_pairBuffer.length) { + that.m_pairBuffer[that.m_pairCount] = new b2DynamicTreePair + } + var pair = that.m_pairBuffer[that.m_pairCount]; + pair.proxyA = proxy < queryProxy ? proxy : queryProxy; + pair.proxyB = proxy >= queryProxy ? proxy : queryProxy; + ++that.m_pairCount; + return true + } + var fatAABB = this.m_tree.GetFatAABB(queryProxy); + this.m_tree.Query(QueryCallback, fatAABB) + } + this.m_moveBuffer.length = 0; + for(var i = 0;i < this.m_pairCount;) { + var primaryPair = this.m_pairBuffer[i]; + var userDataA = this.m_tree.GetUserData(primaryPair.proxyA); + var userDataB = this.m_tree.GetUserData(primaryPair.proxyB); + callback(userDataA, userDataB); + ++i; + while(i < this.m_pairCount) { + var pair = this.m_pairBuffer[i]; + if(pair.proxyA != primaryPair.proxyA || pair.proxyB != primaryPair.proxyB) { + break + } + ++i + } + } +}; +b2DynamicTreeBroadPhase.prototype.Query = function(callback, aabb) { + this.m_tree.Query(callback, aabb) +}; +b2DynamicTreeBroadPhase.prototype.RayCast = function(callback, input) { + this.m_tree.RayCast(callback, input) +}; +b2DynamicTreeBroadPhase.prototype.Validate = function() { +}; +b2DynamicTreeBroadPhase.prototype.Rebalance = function(iterations) { + this.m_tree.Rebalance(iterations) +}; +b2DynamicTreeBroadPhase.prototype.m_tree = new b2DynamicTree; +b2DynamicTreeBroadPhase.prototype.m_proxyCount = 0; +b2DynamicTreeBroadPhase.prototype.m_moveBuffer = new Array; +b2DynamicTreeBroadPhase.prototype.m_pairBuffer = new Array; +b2DynamicTreeBroadPhase.prototype.m_pairCount = 0;var b2BroadPhase = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2BroadPhase.prototype.__constructor = function(worldAABB) { + var i = 0; + this.m_pairManager.Initialize(this); + this.m_worldAABB = worldAABB; + this.m_proxyCount = 0; + this.m_bounds = new Array; + for(i = 0;i < 2;i++) { + this.m_bounds[i] = new Array + } + var dX = worldAABB.upperBound.x - worldAABB.lowerBound.x; + var dY = worldAABB.upperBound.y - worldAABB.lowerBound.y; + this.m_quantizationFactor.x = b2Settings.USHRT_MAX / dX; + this.m_quantizationFactor.y = b2Settings.USHRT_MAX / dY; + this.m_timeStamp = 1; + this.m_queryResultCount = 0 +}; +b2BroadPhase.prototype.__varz = function() { + this.m_pairManager = new b2PairManager; + this.m_proxyPool = new Array; + this.m_querySortKeys = new Array; + this.m_queryResults = new Array; + this.m_quantizationFactor = new b2Vec2 +}; +b2BroadPhase.BinarySearch = function(bounds, count, value) { + var low = 0; + var high = count - 1; + while(low <= high) { + var mid = Math.round((low + high) / 2); + var bound = bounds[mid]; + if(bound.value > value) { + high = mid - 1 + }else { + if(bound.value < value) { + low = mid + 1 + }else { + return parseInt(mid) + } + } + } + return parseInt(low) +}; +b2BroadPhase.s_validate = false; +b2BroadPhase.b2_invalid = b2Settings.USHRT_MAX; +b2BroadPhase.b2_nullEdge = b2Settings.USHRT_MAX; +b2BroadPhase.prototype.ComputeBounds = function(lowerValues, upperValues, aabb) { + var minVertexX = aabb.lowerBound.x; + var minVertexY = aabb.lowerBound.y; + minVertexX = b2Math.Min(minVertexX, this.m_worldAABB.upperBound.x); + minVertexY = b2Math.Min(minVertexY, this.m_worldAABB.upperBound.y); + minVertexX = b2Math.Max(minVertexX, this.m_worldAABB.lowerBound.x); + minVertexY = b2Math.Max(minVertexY, this.m_worldAABB.lowerBound.y); + var maxVertexX = aabb.upperBound.x; + var maxVertexY = aabb.upperBound.y; + maxVertexX = b2Math.Min(maxVertexX, this.m_worldAABB.upperBound.x); + maxVertexY = b2Math.Min(maxVertexY, this.m_worldAABB.upperBound.y); + maxVertexX = b2Math.Max(maxVertexX, this.m_worldAABB.lowerBound.x); + maxVertexY = b2Math.Max(maxVertexY, this.m_worldAABB.lowerBound.y); + lowerValues[0] = parseInt(this.m_quantizationFactor.x * (minVertexX - this.m_worldAABB.lowerBound.x)) & b2Settings.USHRT_MAX - 1; + upperValues[0] = parseInt(this.m_quantizationFactor.x * (maxVertexX - this.m_worldAABB.lowerBound.x)) % 65535 | 1; + lowerValues[1] = parseInt(this.m_quantizationFactor.y * (minVertexY - this.m_worldAABB.lowerBound.y)) & b2Settings.USHRT_MAX - 1; + upperValues[1] = parseInt(this.m_quantizationFactor.y * (maxVertexY - this.m_worldAABB.lowerBound.y)) % 65535 | 1 +}; +b2BroadPhase.prototype.TestOverlapValidate = function(p1, p2) { + for(var axis = 0;axis < 2;++axis) { + var bounds = this.m_bounds[axis]; + var bound1 = bounds[p1.lowerBounds[axis]]; + var bound2 = bounds[p2.upperBounds[axis]]; + if(bound1.value > bound2.value) { + return false + } + bound1 = bounds[p1.upperBounds[axis]]; + bound2 = bounds[p2.lowerBounds[axis]]; + if(bound1.value < bound2.value) { + return false + } + } + return true +}; +b2BroadPhase.prototype.QueryAxis = function(lowerQueryOut, upperQueryOut, lowerValue, upperValue, bounds, boundCount, axis) { + var lowerQuery = b2BroadPhase.BinarySearch(bounds, boundCount, lowerValue); + var upperQuery = b2BroadPhase.BinarySearch(bounds, boundCount, upperValue); + var bound; + for(var j = lowerQuery;j < upperQuery;++j) { + bound = bounds[j]; + if(bound.IsLower()) { + this.IncrementOverlapCount(bound.proxy) + } + } + if(lowerQuery > 0) { + var i = lowerQuery - 1; + bound = bounds[i]; + var s = bound.stabbingCount; + while(s) { + bound = bounds[i]; + if(bound.IsLower()) { + var proxy = bound.proxy; + if(lowerQuery <= proxy.upperBounds[axis]) { + this.IncrementOverlapCount(bound.proxy); + --s + } + } + --i + } + } + lowerQueryOut[0] = lowerQuery; + upperQueryOut[0] = upperQuery +}; +b2BroadPhase.prototype.IncrementOverlapCount = function(proxy) { + if(proxy.timeStamp < this.m_timeStamp) { + proxy.timeStamp = this.m_timeStamp; + proxy.overlapCount = 1 + }else { + proxy.overlapCount = 2; + this.m_queryResults[this.m_queryResultCount] = proxy; + ++this.m_queryResultCount + } +}; +b2BroadPhase.prototype.IncrementTimeStamp = function() { + if(this.m_timeStamp == b2Settings.USHRT_MAX) { + for(var i = 0;i < this.m_proxyPool.length;++i) { + this.m_proxyPool[i].timeStamp = 0 + } + this.m_timeStamp = 1 + }else { + ++this.m_timeStamp + } +}; +b2BroadPhase.prototype.InRange = function(aabb) { + var dX; + var dY; + var d2X; + var d2Y; + dX = aabb.lowerBound.x; + dY = aabb.lowerBound.y; + dX -= this.m_worldAABB.upperBound.x; + dY -= this.m_worldAABB.upperBound.y; + d2X = this.m_worldAABB.lowerBound.x; + d2Y = this.m_worldAABB.lowerBound.y; + d2X -= aabb.upperBound.x; + d2Y -= aabb.upperBound.y; + dX = b2Math.Max(dX, d2X); + dY = b2Math.Max(dY, d2Y); + return b2Math.Max(dX, dY) < 0 +}; +b2BroadPhase.prototype.CreateProxy = function(aabb, userData) { + var index = 0; + var proxy; + var i = 0; + var j = 0; + if(!this.m_freeProxy) { + this.m_freeProxy = this.m_proxyPool[this.m_proxyCount] = new b2Proxy; + this.m_freeProxy.next = null; + this.m_freeProxy.timeStamp = 0; + this.m_freeProxy.overlapCount = b2BroadPhase.b2_invalid; + this.m_freeProxy.userData = null; + for(i = 0;i < 2;i++) { + j = this.m_proxyCount * 2; + this.m_bounds[i][j++] = new b2Bound; + this.m_bounds[i][j] = new b2Bound + } + } + proxy = this.m_freeProxy; + this.m_freeProxy = proxy.next; + proxy.overlapCount = 0; + proxy.userData = userData; + var boundCount = 2 * this.m_proxyCount; + var lowerValues = new Array; + var upperValues = new Array; + this.ComputeBounds(lowerValues, upperValues, aabb); + for(var axis = 0;axis < 2;++axis) { + var bounds = this.m_bounds[axis]; + var lowerIndex = 0; + var upperIndex = 0; + var lowerIndexOut = new Array; + lowerIndexOut.push(lowerIndex); + var upperIndexOut = new Array; + upperIndexOut.push(upperIndex); + this.QueryAxis(lowerIndexOut, upperIndexOut, lowerValues[axis], upperValues[axis], bounds, boundCount, axis); + lowerIndex = lowerIndexOut[0]; + upperIndex = upperIndexOut[0]; + bounds.splice(upperIndex, 0, bounds[bounds.length - 1]); + bounds.length--; + bounds.splice(lowerIndex, 0, bounds[bounds.length - 1]); + bounds.length--; + ++upperIndex; + var tBound1 = bounds[lowerIndex]; + var tBound2 = bounds[upperIndex]; + tBound1.value = lowerValues[axis]; + tBound1.proxy = proxy; + tBound2.value = upperValues[axis]; + tBound2.proxy = proxy; + var tBoundAS3 = bounds[parseInt(lowerIndex - 1)]; + tBound1.stabbingCount = lowerIndex == 0 ? 0 : tBoundAS3.stabbingCount; + tBoundAS3 = bounds[parseInt(upperIndex - 1)]; + tBound2.stabbingCount = tBoundAS3.stabbingCount; + for(index = lowerIndex;index < upperIndex;++index) { + tBoundAS3 = bounds[index]; + tBoundAS3.stabbingCount++ + } + for(index = lowerIndex;index < boundCount + 2;++index) { + tBound1 = bounds[index]; + var proxy2 = tBound1.proxy; + if(tBound1.IsLower()) { + proxy2.lowerBounds[axis] = index + }else { + proxy2.upperBounds[axis] = index + } + } + } + ++this.m_proxyCount; + for(i = 0;i < this.m_queryResultCount;++i) { + this.m_pairManager.AddBufferedPair(proxy, this.m_queryResults[i]) + } + this.m_queryResultCount = 0; + this.IncrementTimeStamp(); + return proxy +}; +b2BroadPhase.prototype.DestroyProxy = function(proxy_) { + var proxy = proxy_; + var tBound1; + var tBound2; + var boundCount = 2 * this.m_proxyCount; + for(var axis = 0;axis < 2;++axis) { + var bounds = this.m_bounds[axis]; + var lowerIndex = proxy.lowerBounds[axis]; + var upperIndex = proxy.upperBounds[axis]; + tBound1 = bounds[lowerIndex]; + var lowerValue = tBound1.value; + tBound2 = bounds[upperIndex]; + var upperValue = tBound2.value; + bounds.splice(upperIndex, 1); + bounds.splice(lowerIndex, 1); + bounds.push(tBound1); + bounds.push(tBound2); + var tEnd = boundCount - 2; + for(var index = lowerIndex;index < tEnd;++index) { + tBound1 = bounds[index]; + var proxy2 = tBound1.proxy; + if(tBound1.IsLower()) { + proxy2.lowerBounds[axis] = index + }else { + proxy2.upperBounds[axis] = index + } + } + tEnd = upperIndex - 1; + for(var index2 = lowerIndex;index2 < tEnd;++index2) { + tBound1 = bounds[index2]; + tBound1.stabbingCount-- + } + var ignore = new Array; + this.QueryAxis(ignore, ignore, lowerValue, upperValue, bounds, boundCount - 2, axis) + } + for(var i = 0;i < this.m_queryResultCount;++i) { + this.m_pairManager.RemoveBufferedPair(proxy, this.m_queryResults[i]) + } + this.m_queryResultCount = 0; + this.IncrementTimeStamp(); + proxy.userData = null; + proxy.overlapCount = b2BroadPhase.b2_invalid; + proxy.lowerBounds[0] = b2BroadPhase.b2_invalid; + proxy.lowerBounds[1] = b2BroadPhase.b2_invalid; + proxy.upperBounds[0] = b2BroadPhase.b2_invalid; + proxy.upperBounds[1] = b2BroadPhase.b2_invalid; + proxy.next = this.m_freeProxy; + this.m_freeProxy = proxy; + --this.m_proxyCount +}; +b2BroadPhase.prototype.MoveProxy = function(proxy_, aabb, displacement) { + var proxy = proxy_; + var as3arr; + var as3int = 0; + var axis = 0; + var index = 0; + var bound; + var prevBound; + var nextBound; + var nextProxyId = 0; + var nextProxy; + if(proxy == null) { + return + } + if(aabb.IsValid() == false) { + return + } + var boundCount = 2 * this.m_proxyCount; + var newValues = new b2BoundValues; + this.ComputeBounds(newValues.lowerValues, newValues.upperValues, aabb); + var oldValues = new b2BoundValues; + for(axis = 0;axis < 2;++axis) { + bound = this.m_bounds[axis][proxy.lowerBounds[axis]]; + oldValues.lowerValues[axis] = bound.value; + bound = this.m_bounds[axis][proxy.upperBounds[axis]]; + oldValues.upperValues[axis] = bound.value + } + for(axis = 0;axis < 2;++axis) { + var bounds = this.m_bounds[axis]; + var lowerIndex = proxy.lowerBounds[axis]; + var upperIndex = proxy.upperBounds[axis]; + var lowerValue = newValues.lowerValues[axis]; + var upperValue = newValues.upperValues[axis]; + bound = bounds[lowerIndex]; + var deltaLower = lowerValue - bound.value; + bound.value = lowerValue; + bound = bounds[upperIndex]; + var deltaUpper = upperValue - bound.value; + bound.value = upperValue; + if(deltaLower < 0) { + index = lowerIndex; + while(index > 0 && lowerValue < bounds[parseInt(index - 1)].value) { + bound = bounds[index]; + prevBound = bounds[parseInt(index - 1)]; + var prevProxy = prevBound.proxy; + prevBound.stabbingCount++; + if(prevBound.IsUpper() == true) { + if(this.TestOverlapBound(newValues, prevProxy)) { + this.m_pairManager.AddBufferedPair(proxy, prevProxy) + } + as3arr = prevProxy.upperBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + bound.stabbingCount++ + }else { + as3arr = prevProxy.lowerBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + bound.stabbingCount-- + } + as3arr = proxy.lowerBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + bound.Swap(prevBound); + --index + } + } + if(deltaUpper > 0) { + index = upperIndex; + while(index < boundCount - 1 && bounds[parseInt(index + 1)].value <= upperValue) { + bound = bounds[index]; + nextBound = bounds[parseInt(index + 1)]; + nextProxy = nextBound.proxy; + nextBound.stabbingCount++; + if(nextBound.IsLower() == true) { + if(this.TestOverlapBound(newValues, nextProxy)) { + this.m_pairManager.AddBufferedPair(proxy, nextProxy) + } + as3arr = nextProxy.lowerBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + bound.stabbingCount++ + }else { + as3arr = nextProxy.upperBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + bound.stabbingCount-- + } + as3arr = proxy.upperBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + bound.Swap(nextBound); + index++ + } + } + if(deltaLower > 0) { + index = lowerIndex; + while(index < boundCount - 1 && bounds[parseInt(index + 1)].value <= lowerValue) { + bound = bounds[index]; + nextBound = bounds[parseInt(index + 1)]; + nextProxy = nextBound.proxy; + nextBound.stabbingCount--; + if(nextBound.IsUpper()) { + if(this.TestOverlapBound(oldValues, nextProxy)) { + this.m_pairManager.RemoveBufferedPair(proxy, nextProxy) + } + as3arr = nextProxy.upperBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + bound.stabbingCount-- + }else { + as3arr = nextProxy.lowerBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + bound.stabbingCount++ + } + as3arr = proxy.lowerBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + bound.Swap(nextBound); + index++ + } + } + if(deltaUpper < 0) { + index = upperIndex; + while(index > 0 && upperValue < bounds[parseInt(index - 1)].value) { + bound = bounds[index]; + prevBound = bounds[parseInt(index - 1)]; + prevProxy = prevBound.proxy; + prevBound.stabbingCount--; + if(prevBound.IsLower() == true) { + if(this.TestOverlapBound(oldValues, prevProxy)) { + this.m_pairManager.RemoveBufferedPair(proxy, prevProxy) + } + as3arr = prevProxy.lowerBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + bound.stabbingCount-- + }else { + as3arr = prevProxy.upperBounds; + as3int = as3arr[axis]; + as3int++; + as3arr[axis] = as3int; + bound.stabbingCount++ + } + as3arr = proxy.upperBounds; + as3int = as3arr[axis]; + as3int--; + as3arr[axis] = as3int; + bound.Swap(prevBound); + index-- + } + } + } +}; +b2BroadPhase.prototype.UpdatePairs = function(callback) { + this.m_pairManager.Commit(callback) +}; +b2BroadPhase.prototype.TestOverlap = function(proxyA, proxyB) { + var proxyA_ = proxyA; + var proxyB_ = proxyB; + if(proxyA_.lowerBounds[0] > proxyB_.upperBounds[0]) { + return false + } + if(proxyB_.lowerBounds[0] > proxyA_.upperBounds[0]) { + return false + } + if(proxyA_.lowerBounds[1] > proxyB_.upperBounds[1]) { + return false + } + if(proxyB_.lowerBounds[1] > proxyA_.upperBounds[1]) { + return false + } + return true +}; +b2BroadPhase.prototype.GetUserData = function(proxy) { + return proxy.userData +}; +b2BroadPhase.prototype.GetFatAABB = function(proxy_) { + var aabb = new b2AABB; + var proxy = proxy_; + aabb.lowerBound.x = this.m_worldAABB.lowerBound.x + this.m_bounds[0][proxy.lowerBounds[0]].value / this.m_quantizationFactor.x; + aabb.lowerBound.y = this.m_worldAABB.lowerBound.y + this.m_bounds[1][proxy.lowerBounds[1]].value / this.m_quantizationFactor.y; + aabb.upperBound.x = this.m_worldAABB.lowerBound.x + this.m_bounds[0][proxy.upperBounds[0]].value / this.m_quantizationFactor.x; + aabb.upperBound.y = this.m_worldAABB.lowerBound.y + this.m_bounds[1][proxy.upperBounds[1]].value / this.m_quantizationFactor.y; + return aabb +}; +b2BroadPhase.prototype.GetProxyCount = function() { + return this.m_proxyCount +}; +b2BroadPhase.prototype.Query = function(callback, aabb) { + var lowerValues = new Array; + var upperValues = new Array; + this.ComputeBounds(lowerValues, upperValues, aabb); + var lowerIndex = 0; + var upperIndex = 0; + var lowerIndexOut = new Array; + lowerIndexOut.push(lowerIndex); + var upperIndexOut = new Array; + upperIndexOut.push(upperIndex); + this.QueryAxis(lowerIndexOut, upperIndexOut, lowerValues[0], upperValues[0], this.m_bounds[0], 2 * this.m_proxyCount, 0); + this.QueryAxis(lowerIndexOut, upperIndexOut, lowerValues[1], upperValues[1], this.m_bounds[1], 2 * this.m_proxyCount, 1); + for(var i = 0;i < this.m_queryResultCount;++i) { + var proxy = this.m_queryResults[i]; + if(!callback(proxy)) { + break + } + } + this.m_queryResultCount = 0; + this.IncrementTimeStamp() +}; +b2BroadPhase.prototype.Validate = function() { + var pair; + var proxy1; + var proxy2; + var overlap; + for(var axis = 0;axis < 2;++axis) { + var bounds = this.m_bounds[axis]; + var boundCount = 2 * this.m_proxyCount; + var stabbingCount = 0; + for(var i = 0;i < boundCount;++i) { + var bound = bounds[i]; + if(bound.IsLower() == true) { + stabbingCount++ + }else { + stabbingCount-- + } + } + } +}; +b2BroadPhase.prototype.Rebalance = function(iterations) { +}; +b2BroadPhase.prototype.RayCast = function(callback, input) { + var subInput = new b2RayCastInput; + subInput.p1.SetV(input.p1); + subInput.p2.SetV(input.p2); + subInput.maxFraction = input.maxFraction; + var dx = (input.p2.x - input.p1.x) * this.m_quantizationFactor.x; + var dy = (input.p2.y - input.p1.y) * this.m_quantizationFactor.y; + var sx = dx < -Number.MIN_VALUE ? -1 : dx > Number.MIN_VALUE ? 1 : 0; + var sy = dy < -Number.MIN_VALUE ? -1 : dy > Number.MIN_VALUE ? 1 : 0; + var p1x = this.m_quantizationFactor.x * (input.p1.x - this.m_worldAABB.lowerBound.x); + var p1y = this.m_quantizationFactor.y * (input.p1.y - this.m_worldAABB.lowerBound.y); + var startValues = new Array; + var startValues2 = new Array; + startValues[0] = parseInt(p1x) & b2Settings.USHRT_MAX - 1; + startValues[1] = parseInt(p1y) & b2Settings.USHRT_MAX - 1; + startValues2[0] = startValues[0] + 1; + startValues2[1] = startValues[1] + 1; + var startIndices = new Array; + var xIndex = 0; + var yIndex = 0; + var proxy; + var lowerIndex = 0; + var upperIndex = 0; + var lowerIndexOut = new Array; + lowerIndexOut.push(lowerIndex); + var upperIndexOut = new Array; + upperIndexOut.push(upperIndex); + this.QueryAxis(lowerIndexOut, upperIndexOut, startValues[0], startValues2[0], this.m_bounds[0], 2 * this.m_proxyCount, 0); + if(sx >= 0) { + xIndex = upperIndexOut[0] - 1 + }else { + xIndex = lowerIndexOut[0] + } + this.QueryAxis(lowerIndexOut, upperIndexOut, startValues[1], startValues2[1], this.m_bounds[1], 2 * this.m_proxyCount, 1); + if(sy >= 0) { + yIndex = upperIndexOut[0] - 1 + }else { + yIndex = lowerIndexOut[0] + } + for(var i = 0;i < this.m_queryResultCount;i++) { + subInput.maxFraction = callback(this.m_queryResults[i], subInput) + } + for(;;) { + var xProgress = 0; + var yProgress = 0; + xIndex += sx >= 0 ? 1 : -1; + if(xIndex < 0 || xIndex >= this.m_proxyCount * 2) { + break + } + if(sx != 0) { + xProgress = (this.m_bounds[0][xIndex].value - p1x) / dx + } + yIndex += sy >= 0 ? 1 : -1; + if(yIndex < 0 || yIndex >= this.m_proxyCount * 2) { + break + } + if(sy != 0) { + yProgress = (this.m_bounds[1][yIndex].value - p1y) / dy + } + for(;;) { + if(sy == 0 || sx != 0 && xProgress < yProgress) { + if(xProgress > subInput.maxFraction) { + break + } + if(sx > 0 ? this.m_bounds[0][xIndex].IsLower() : this.m_bounds[0][xIndex].IsUpper()) { + proxy = this.m_bounds[0][xIndex].proxy; + if(sy >= 0) { + if(proxy.lowerBounds[1] <= yIndex - 1 && proxy.upperBounds[1] >= yIndex) { + subInput.maxFraction = callback(proxy, subInput) + } + }else { + if(proxy.lowerBounds[1] <= yIndex && proxy.upperBounds[1] >= yIndex + 1) { + subInput.maxFraction = callback(proxy, subInput) + } + } + } + if(subInput.maxFraction == 0) { + break + } + if(sx > 0) { + xIndex++; + if(xIndex == this.m_proxyCount * 2) { + break + } + }else { + xIndex--; + if(xIndex < 0) { + break + } + } + xProgress = (this.m_bounds[0][xIndex].value - p1x) / dx + }else { + if(yProgress > subInput.maxFraction) { + break + } + if(sy > 0 ? this.m_bounds[1][yIndex].IsLower() : this.m_bounds[1][yIndex].IsUpper()) { + proxy = this.m_bounds[1][yIndex].proxy; + if(sx >= 0) { + if(proxy.lowerBounds[0] <= xIndex - 1 && proxy.upperBounds[0] >= xIndex) { + subInput.maxFraction = callback(proxy, subInput) + } + }else { + if(proxy.lowerBounds[0] <= xIndex && proxy.upperBounds[0] >= xIndex + 1) { + subInput.maxFraction = callback(proxy, subInput) + } + } + } + if(subInput.maxFraction == 0) { + break + } + if(sy > 0) { + yIndex++; + if(yIndex == this.m_proxyCount * 2) { + break + } + }else { + yIndex--; + if(yIndex < 0) { + break + } + } + yProgress = (this.m_bounds[1][yIndex].value - p1y) / dy + } + } + break + } + this.m_queryResultCount = 0; + this.IncrementTimeStamp(); + return +}; +b2BroadPhase.prototype.TestOverlapBound = function(b, p) { + for(var axis = 0;axis < 2;++axis) { + var bounds = this.m_bounds[axis]; + var bound = bounds[p.upperBounds[axis]]; + if(b.lowerValues[axis] > bound.value) { + return false + } + bound = bounds[p.lowerBounds[axis]]; + if(b.upperValues[axis] < bound.value) { + return false + } + } + return true +}; +b2BroadPhase.prototype.m_pairManager = new b2PairManager; +b2BroadPhase.prototype.m_proxyPool = new Array; +b2BroadPhase.prototype.m_freeProxy = null; +b2BroadPhase.prototype.m_bounds = null; +b2BroadPhase.prototype.m_querySortKeys = new Array; +b2BroadPhase.prototype.m_queryResults = new Array; +b2BroadPhase.prototype.m_queryResultCount = 0; +b2BroadPhase.prototype.m_worldAABB = null; +b2BroadPhase.prototype.m_quantizationFactor = new b2Vec2; +b2BroadPhase.prototype.m_proxyCount = 0; +b2BroadPhase.prototype.m_timeStamp = 0;var b2Manifold = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Manifold.prototype.__constructor = function() { + this.m_points = new Array(b2Settings.b2_maxManifoldPoints); + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;i++) { + this.m_points[i] = new b2ManifoldPoint + } + this.m_localPlaneNormal = new b2Vec2; + this.m_localPoint = new b2Vec2 +}; +b2Manifold.prototype.__varz = function() { +}; +b2Manifold.e_circles = 1; +b2Manifold.e_faceA = 2; +b2Manifold.e_faceB = 4; +b2Manifold.prototype.Reset = function() { + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;i++) { + this.m_points[i].Reset() + } + this.m_localPlaneNormal.SetZero(); + this.m_localPoint.SetZero(); + this.m_type = 0; + this.m_pointCount = 0 +}; +b2Manifold.prototype.Set = function(m) { + this.m_pointCount = m.m_pointCount; + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;i++) { + this.m_points[i].Set(m.m_points[i]) + } + this.m_localPlaneNormal.SetV(m.m_localPlaneNormal); + this.m_localPoint.SetV(m.m_localPoint); + this.m_type = m.m_type +}; +b2Manifold.prototype.Copy = function() { + var copy = new b2Manifold; + copy.Set(this); + return copy +}; +b2Manifold.prototype.m_points = null; +b2Manifold.prototype.m_localPlaneNormal = null; +b2Manifold.prototype.m_localPoint = null; +b2Manifold.prototype.m_type = 0; +b2Manifold.prototype.m_pointCount = 0;var b2CircleShape = function() { + b2Shape.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2CircleShape.prototype, b2Shape.prototype); +b2CircleShape.prototype._super = b2Shape.prototype; +b2CircleShape.prototype.__constructor = function(radius) { + this._super.__constructor.apply(this, []); + this.m_type = b2Shape.e_circleShape; + this.m_radius = radius +}; +b2CircleShape.prototype.__varz = function() { + this.m_p = new b2Vec2 +}; +b2CircleShape.prototype.Copy = function() { + var s = new b2CircleShape; + s.Set(this); + return s +}; +b2CircleShape.prototype.Set = function(other) { + this._super.Set.apply(this, [other]); + if(isInstanceOf(other, b2CircleShape)) { + var other2 = other; + this.m_p.SetV(other2.m_p) + } +}; +b2CircleShape.prototype.TestPoint = function(transform, p) { + var tMat = transform.R; + var dX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); + var dY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); + dX = p.x - dX; + dY = p.y - dY; + return dX * dX + dY * dY <= this.m_radius * this.m_radius +}; +b2CircleShape.prototype.RayCast = function(output, input, transform) { + var tMat = transform.R; + var positionX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); + var positionY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); + var sX = input.p1.x - positionX; + var sY = input.p1.y - positionY; + var b = sX * sX + sY * sY - this.m_radius * this.m_radius; + var rX = input.p2.x - input.p1.x; + var rY = input.p2.y - input.p1.y; + var c = sX * rX + sY * rY; + var rr = rX * rX + rY * rY; + var sigma = c * c - rr * b; + if(sigma < 0 || rr < Number.MIN_VALUE) { + return false + } + var a = -(c + Math.sqrt(sigma)); + if(0 <= a && a <= input.maxFraction * rr) { + a /= rr; + output.fraction = a; + output.normal.x = sX + a * rX; + output.normal.y = sY + a * rY; + output.normal.Normalize(); + return true + } + return false +}; +b2CircleShape.prototype.ComputeAABB = function(aabb, transform) { + var tMat = transform.R; + var pX = transform.position.x + (tMat.col1.x * this.m_p.x + tMat.col2.x * this.m_p.y); + var pY = transform.position.y + (tMat.col1.y * this.m_p.x + tMat.col2.y * this.m_p.y); + aabb.lowerBound.Set(pX - this.m_radius, pY - this.m_radius); + aabb.upperBound.Set(pX + this.m_radius, pY + this.m_radius) +}; +b2CircleShape.prototype.ComputeMass = function(massData, density) { + massData.mass = density * b2Settings.b2_pi * this.m_radius * this.m_radius; + massData.center.SetV(this.m_p); + massData.I = massData.mass * (0.5 * this.m_radius * this.m_radius + (this.m_p.x * this.m_p.x + this.m_p.y * this.m_p.y)) +}; +b2CircleShape.prototype.ComputeSubmergedArea = function(normal, offset, xf, c) { + var p = b2Math.MulX(xf, this.m_p); + var l = -(b2Math.Dot(normal, p) - offset); + if(l < -this.m_radius + Number.MIN_VALUE) { + return 0 + } + if(l > this.m_radius) { + c.SetV(p); + return Math.PI * this.m_radius * this.m_radius + } + var r2 = this.m_radius * this.m_radius; + var l2 = l * l; + var area = r2 * (Math.asin(l / this.m_radius) + Math.PI / 2) + l * Math.sqrt(r2 - l2); + var com = -2 / 3 * Math.pow(r2 - l2, 1.5) / area; + c.x = p.x + normal.x * com; + c.y = p.y + normal.y * com; + return area +}; +b2CircleShape.prototype.GetLocalPosition = function() { + return this.m_p +}; +b2CircleShape.prototype.SetLocalPosition = function(position) { + this.m_p.SetV(position) +}; +b2CircleShape.prototype.GetRadius = function() { + return this.m_radius +}; +b2CircleShape.prototype.SetRadius = function(radius) { + this.m_radius = radius +}; +b2CircleShape.prototype.m_p = new b2Vec2;var b2Joint = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Joint.prototype.__constructor = function(def) { + b2Settings.b2Assert(def.bodyA != def.bodyB); + this.m_type = def.type; + this.m_prev = null; + this.m_next = null; + this.m_bodyA = def.bodyA; + this.m_bodyB = def.bodyB; + this.m_collideConnected = def.collideConnected; + this.m_islandFlag = false; + this.m_userData = def.userData +}; +b2Joint.prototype.__varz = function() { + this.m_edgeA = new b2JointEdge; + this.m_edgeB = new b2JointEdge; + this.m_localCenterA = new b2Vec2; + this.m_localCenterB = new b2Vec2 +}; +b2Joint.Create = function(def, allocator) { + var joint = null; + switch(def.type) { + case b2Joint.e_distanceJoint: + joint = new b2DistanceJoint(def); + break; + case b2Joint.e_mouseJoint: + joint = new b2MouseJoint(def); + break; + case b2Joint.e_prismaticJoint: + joint = new b2PrismaticJoint(def); + break; + case b2Joint.e_revoluteJoint: + joint = new b2RevoluteJoint(def); + break; + case b2Joint.e_pulleyJoint: + joint = new b2PulleyJoint(def); + break; + case b2Joint.e_gearJoint: + joint = new b2GearJoint(def); + break; + case b2Joint.e_lineJoint: + joint = new b2LineJoint(def); + break; + case b2Joint.e_weldJoint: + joint = new b2WeldJoint(def); + break; + case b2Joint.e_frictionJoint: + joint = new b2FrictionJoint(def); + break; + default: + break + } + return joint +}; +b2Joint.Destroy = function(joint, allocator) { +}; +b2Joint.e_unknownJoint = 0; +b2Joint.e_revoluteJoint = 1; +b2Joint.e_prismaticJoint = 2; +b2Joint.e_distanceJoint = 3; +b2Joint.e_pulleyJoint = 4; +b2Joint.e_mouseJoint = 5; +b2Joint.e_gearJoint = 6; +b2Joint.e_lineJoint = 7; +b2Joint.e_weldJoint = 8; +b2Joint.e_frictionJoint = 9; +b2Joint.e_inactiveLimit = 0; +b2Joint.e_atLowerLimit = 1; +b2Joint.e_atUpperLimit = 2; +b2Joint.e_equalLimits = 3; +b2Joint.prototype.InitVelocityConstraints = function(step) { +}; +b2Joint.prototype.SolveVelocityConstraints = function(step) { +}; +b2Joint.prototype.FinalizeVelocityConstraints = function() { +}; +b2Joint.prototype.SolvePositionConstraints = function(baumgarte) { + return false +}; +b2Joint.prototype.GetType = function() { + return this.m_type +}; +b2Joint.prototype.GetAnchorA = function() { + return null +}; +b2Joint.prototype.GetAnchorB = function() { + return null +}; +b2Joint.prototype.GetReactionForce = function(inv_dt) { + return null +}; +b2Joint.prototype.GetReactionTorque = function(inv_dt) { + return 0 +}; +b2Joint.prototype.GetBodyA = function() { + return this.m_bodyA +}; +b2Joint.prototype.GetBodyB = function() { + return this.m_bodyB +}; +b2Joint.prototype.GetNext = function() { + return this.m_next +}; +b2Joint.prototype.GetUserData = function() { + return this.m_userData +}; +b2Joint.prototype.SetUserData = function(data) { + this.m_userData = data +}; +b2Joint.prototype.IsActive = function() { + return this.m_bodyA.IsActive() && this.m_bodyB.IsActive() +}; +b2Joint.prototype.m_type = 0; +b2Joint.prototype.m_prev = null; +b2Joint.prototype.m_next = null; +b2Joint.prototype.m_edgeA = new b2JointEdge; +b2Joint.prototype.m_edgeB = new b2JointEdge; +b2Joint.prototype.m_bodyA = null; +b2Joint.prototype.m_bodyB = null; +b2Joint.prototype.m_islandFlag = null; +b2Joint.prototype.m_collideConnected = null; +b2Joint.prototype.m_userData = null; +b2Joint.prototype.m_localCenterA = new b2Vec2; +b2Joint.prototype.m_localCenterB = new b2Vec2; +b2Joint.prototype.m_invMassA = null; +b2Joint.prototype.m_invMassB = null; +b2Joint.prototype.m_invIA = null; +b2Joint.prototype.m_invIB = null;var b2LineJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2LineJoint.prototype, b2Joint.prototype); +b2LineJoint.prototype._super = b2Joint.prototype; +b2LineJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + var tMat; + var tX; + var tY; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_localXAxis1.SetV(def.localAxisA); + this.m_localYAxis1.x = -this.m_localXAxis1.y; + this.m_localYAxis1.y = this.m_localXAxis1.x; + this.m_impulse.SetZero(); + this.m_motorMass = 0; + this.m_motorImpulse = 0; + this.m_lowerTranslation = def.lowerTranslation; + this.m_upperTranslation = def.upperTranslation; + this.m_maxMotorForce = def.maxMotorForce; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_axis.SetZero(); + this.m_perp.SetZero() +}; +b2LineJoint.prototype.__varz = function() { + this.m_localAnchor1 = new b2Vec2; + this.m_localAnchor2 = new b2Vec2; + this.m_localXAxis1 = new b2Vec2; + this.m_localYAxis1 = new b2Vec2; + this.m_axis = new b2Vec2; + this.m_perp = new b2Vec2; + this.m_K = new b2Mat22; + this.m_impulse = new b2Vec2 +}; +b2LineJoint.prototype.InitVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX; + this.m_localCenterA.SetV(bA.GetLocalCenter()); + this.m_localCenterB.SetV(bB.GetLocalCenter()); + var xf1 = bA.GetTransform(); + var xf2 = bB.GetTransform(); + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + this.m_invMassA = bA.m_invMass; + this.m_invMassB = bB.m_invMass; + this.m_invIA = bA.m_invI; + this.m_invIB = bB.m_invI; + this.m_axis.SetV(b2Math.MulMV(xf1.R, this.m_localXAxis1)); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + this.m_motorMass = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_a1 * this.m_a1 + this.m_invIB * this.m_a2 * this.m_a2; + this.m_motorMass = this.m_motorMass > Number.MIN_VALUE ? 1 / this.m_motorMass : 0; + this.m_perp.SetV(b2Math.MulMV(xf1.R, this.m_localYAxis1)); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var m1 = this.m_invMassA; + var m2 = this.m_invMassB; + var i1 = this.m_invIA; + var i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + if(this.m_enableLimit) { + var jointTransition = this.m_axis.x * dX + this.m_axis.y * dY; + if(b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2 * b2Settings.b2_linearSlop) { + this.m_limitState = b2Joint.e_equalLimits + }else { + if(jointTransition <= this.m_lowerTranslation) { + if(this.m_limitState != b2Joint.e_atLowerLimit) { + this.m_limitState = b2Joint.e_atLowerLimit; + this.m_impulse.y = 0 + } + }else { + if(jointTransition >= this.m_upperTranslation) { + if(this.m_limitState != b2Joint.e_atUpperLimit) { + this.m_limitState = b2Joint.e_atUpperLimit; + this.m_impulse.y = 0 + } + }else { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_impulse.y = 0 + } + } + } + }else { + this.m_limitState = b2Joint.e_inactiveLimit + } + if(this.m_enableMotor == false) { + this.m_motorImpulse = 0 + } + if(step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_motorImpulse *= step.dtRatio; + var PX = this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.x; + var PY = this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.y; + var L1 = this.m_impulse.x * this.m_s1 + (this.m_motorImpulse + this.m_impulse.y) * this.m_a1; + var L2 = this.m_impulse.x * this.m_s2 + (this.m_motorImpulse + this.m_impulse.y) * this.m_a2; + bA.m_linearVelocity.x -= this.m_invMassA * PX; + bA.m_linearVelocity.y -= this.m_invMassA * PY; + bA.m_angularVelocity -= this.m_invIA * L1; + bB.m_linearVelocity.x += this.m_invMassB * PX; + bB.m_linearVelocity.y += this.m_invMassB * PY; + bB.m_angularVelocity += this.m_invIB * L2 + }else { + this.m_impulse.SetZero(); + this.m_motorImpulse = 0 + } +}; +b2LineJoint.prototype.SolveVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var v1 = bA.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var v2 = bB.m_linearVelocity; + var w2 = bB.m_angularVelocity; + var PX; + var PY; + var L1; + var L2; + if(this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { + var Cdot = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot); + var oldImpulse = this.m_motorImpulse; + var maxImpulse = step.dt * this.m_maxMotorForce; + this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = this.m_motorImpulse - oldImpulse; + PX = impulse * this.m_axis.x; + PY = impulse * this.m_axis.y; + L1 = impulse * this.m_a1; + L2 = impulse * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2 + } + var Cdot1 = this.m_perp.x * (v2.x - v1.x) + this.m_perp.y * (v2.y - v1.y) + this.m_s2 * w2 - this.m_s1 * w1; + if(this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + var Cdot2 = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var f1 = this.m_impulse.Copy(); + var df = this.m_K.Solve(new b2Vec2, -Cdot1, -Cdot2); + this.m_impulse.Add(df); + if(this.m_limitState == b2Joint.e_atLowerLimit) { + this.m_impulse.y = b2Math.Max(this.m_impulse.y, 0) + }else { + if(this.m_limitState == b2Joint.e_atUpperLimit) { + this.m_impulse.y = b2Math.Min(this.m_impulse.y, 0) + } + } + var b = -Cdot1 - (this.m_impulse.y - f1.y) * this.m_K.col2.x; + var f2r; + if(this.m_K.col1.x != 0) { + f2r = b / this.m_K.col1.x + f1.x + }else { + f2r = f1.x + } + this.m_impulse.x = f2r; + df.x = this.m_impulse.x - f1.x; + df.y = this.m_impulse.y - f1.y; + PX = df.x * this.m_perp.x + df.y * this.m_axis.x; + PY = df.x * this.m_perp.y + df.y * this.m_axis.y; + L1 = df.x * this.m_s1 + df.y * this.m_a1; + L2 = df.x * this.m_s2 + df.y * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2 + }else { + var df2; + if(this.m_K.col1.x != 0) { + df2 = -Cdot1 / this.m_K.col1.x + }else { + df2 = 0 + } + this.m_impulse.x += df2; + PX = df2 * this.m_perp.x; + PY = df2 * this.m_perp.y; + L1 = df2 * this.m_s1; + L2 = df2 * this.m_s2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2 + } + bA.m_linearVelocity.SetV(v1); + bA.m_angularVelocity = w1; + bB.m_linearVelocity.SetV(v2); + bB.m_angularVelocity = w2 +}; +b2LineJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var limitC; + var oldLimitImpulse; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var c1 = bA.m_sweep.c; + var a1 = bA.m_sweep.a; + var c2 = bB.m_sweep.c; + var a2 = bB.m_sweep.a; + var tMat; + var tX; + var m1; + var m2; + var i1; + var i2; + var linearError = 0; + var angularError = 0; + var active = false; + var C2 = 0; + var R1 = b2Mat22.FromAngle(a1); + var R2 = b2Mat22.FromAngle(a2); + tMat = R1; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = R2; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var dX = c2.x + r2X - c1.x - r1X; + var dY = c2.y + r2Y - c1.y - r1Y; + if(this.m_enableLimit) { + this.m_axis = b2Math.MulMV(R1, this.m_localXAxis1); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + var translation = this.m_axis.x * dX + this.m_axis.y * dY; + if(b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2 * b2Settings.b2_linearSlop) { + C2 = b2Math.Clamp(translation, -b2Settings.b2_maxLinearCorrection, b2Settings.b2_maxLinearCorrection); + linearError = b2Math.Abs(translation); + active = true + }else { + if(translation <= this.m_lowerTranslation) { + C2 = b2Math.Clamp(translation - this.m_lowerTranslation + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0); + linearError = this.m_lowerTranslation - translation; + active = true + }else { + if(translation >= this.m_upperTranslation) { + C2 = b2Math.Clamp(translation - this.m_upperTranslation + b2Settings.b2_linearSlop, 0, b2Settings.b2_maxLinearCorrection); + linearError = translation - this.m_upperTranslation; + active = true + } + } + } + } + this.m_perp = b2Math.MulMV(R1, this.m_localYAxis1); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var impulse = new b2Vec2; + var C1 = this.m_perp.x * dX + this.m_perp.y * dY; + linearError = b2Math.Max(linearError, b2Math.Abs(C1)); + angularError = 0; + if(active) { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + this.m_K.Solve(impulse, -C1, -C2) + }else { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + var k11 = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + var impulse1; + if(k11 != 0) { + impulse1 = -C1 / k11 + }else { + impulse1 = 0 + } + impulse.x = impulse1; + impulse.y = 0 + } + var PX = impulse.x * this.m_perp.x + impulse.y * this.m_axis.x; + var PY = impulse.x * this.m_perp.y + impulse.y * this.m_axis.y; + var L1 = impulse.x * this.m_s1 + impulse.y * this.m_a1; + var L2 = impulse.x * this.m_s2 + impulse.y * this.m_a2; + c1.x -= this.m_invMassA * PX; + c1.y -= this.m_invMassA * PY; + a1 -= this.m_invIA * L1; + c2.x += this.m_invMassB * PX; + c2.y += this.m_invMassB * PY; + a2 += this.m_invIB * L2; + bA.m_sweep.a = a1; + bB.m_sweep.a = a2; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return linearError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop +}; +b2LineJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1) +}; +b2LineJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2) +}; +b2LineJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * (this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.x), inv_dt * (this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.y) * this.m_axis.y)) +}; +b2LineJoint.prototype.GetReactionTorque = function(inv_dt) { + return inv_dt * this.m_impulse.y +}; +b2LineJoint.prototype.GetJointTranslation = function() { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var p1 = bA.GetWorldPoint(this.m_localAnchor1); + var p2 = bB.GetWorldPoint(this.m_localAnchor2); + var dX = p2.x - p1.x; + var dY = p2.y - p1.y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var translation = axis.x * dX + axis.y * dY; + return translation +}; +b2LineJoint.prototype.GetJointSpeed = function() { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var p1X = bA.m_sweep.c.x + r1X; + var p1Y = bA.m_sweep.c.y + r1Y; + var p2X = bB.m_sweep.c.x + r2X; + var p2Y = bB.m_sweep.c.y + r2Y; + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var v1 = bA.m_linearVelocity; + var v2 = bB.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var w2 = bB.m_angularVelocity; + var speed = dX * -w1 * axis.y + dY * w1 * axis.x + (axis.x * (v2.x + -w2 * r2Y - v1.x - -w1 * r1Y) + axis.y * (v2.y + w2 * r2X - v1.y - w1 * r1X)); + return speed +}; +b2LineJoint.prototype.IsLimitEnabled = function() { + return this.m_enableLimit +}; +b2LineJoint.prototype.EnableLimit = function(flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableLimit = flag +}; +b2LineJoint.prototype.GetLowerLimit = function() { + return this.m_lowerTranslation +}; +b2LineJoint.prototype.GetUpperLimit = function() { + return this.m_upperTranslation +}; +b2LineJoint.prototype.SetLimits = function(lower, upper) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_lowerTranslation = lower; + this.m_upperTranslation = upper +}; +b2LineJoint.prototype.IsMotorEnabled = function() { + return this.m_enableMotor +}; +b2LineJoint.prototype.EnableMotor = function(flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableMotor = flag +}; +b2LineJoint.prototype.SetMotorSpeed = function(speed) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_motorSpeed = speed +}; +b2LineJoint.prototype.GetMotorSpeed = function() { + return this.m_motorSpeed +}; +b2LineJoint.prototype.SetMaxMotorForce = function(force) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_maxMotorForce = force +}; +b2LineJoint.prototype.GetMaxMotorForce = function() { + return this.m_maxMotorForce +}; +b2LineJoint.prototype.GetMotorForce = function() { + return this.m_motorImpulse +}; +b2LineJoint.prototype.m_localAnchor1 = new b2Vec2; +b2LineJoint.prototype.m_localAnchor2 = new b2Vec2; +b2LineJoint.prototype.m_localXAxis1 = new b2Vec2; +b2LineJoint.prototype.m_localYAxis1 = new b2Vec2; +b2LineJoint.prototype.m_axis = new b2Vec2; +b2LineJoint.prototype.m_perp = new b2Vec2; +b2LineJoint.prototype.m_s1 = null; +b2LineJoint.prototype.m_s2 = null; +b2LineJoint.prototype.m_a1 = null; +b2LineJoint.prototype.m_a2 = null; +b2LineJoint.prototype.m_K = new b2Mat22; +b2LineJoint.prototype.m_impulse = new b2Vec2; +b2LineJoint.prototype.m_motorMass = null; +b2LineJoint.prototype.m_motorImpulse = null; +b2LineJoint.prototype.m_lowerTranslation = null; +b2LineJoint.prototype.m_upperTranslation = null; +b2LineJoint.prototype.m_maxMotorForce = null; +b2LineJoint.prototype.m_motorSpeed = null; +b2LineJoint.prototype.m_enableLimit = null; +b2LineJoint.prototype.m_enableMotor = null; +b2LineJoint.prototype.m_limitState = 0;var b2ContactSolver = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactSolver.prototype.__constructor = function() { +}; +b2ContactSolver.prototype.__varz = function() { + this.m_step = new b2TimeStep; + this.m_constraints = new Array +}; +b2ContactSolver.s_worldManifold = new b2WorldManifold; +b2ContactSolver.s_psm = new b2PositionSolverManifold; +b2ContactSolver.prototype.Initialize = function(step, contacts, contactCount, allocator) { + var contact; + this.m_step.Set(step); + this.m_allocator = allocator; + var i = 0; + var tVec; + var tMat; + this.m_constraintCount = contactCount; + while(this.m_constraints.length < this.m_constraintCount) { + this.m_constraints[this.m_constraints.length] = new b2ContactConstraint + } + for(i = 0;i < contactCount;++i) { + contact = contacts[i]; + var fixtureA = contact.m_fixtureA; + var fixtureB = contact.m_fixtureB; + var shapeA = fixtureA.m_shape; + var shapeB = fixtureB.m_shape; + var radiusA = shapeA.m_radius; + var radiusB = shapeB.m_radius; + var bodyA = fixtureA.m_body; + var bodyB = fixtureB.m_body; + var manifold = contact.GetManifold(); + var friction = b2Settings.b2MixFriction(fixtureA.GetFriction(), fixtureB.GetFriction()); + var restitution = b2Settings.b2MixRestitution(fixtureA.GetRestitution(), fixtureB.GetRestitution()); + var vAX = bodyA.m_linearVelocity.x; + var vAY = bodyA.m_linearVelocity.y; + var vBX = bodyB.m_linearVelocity.x; + var vBY = bodyB.m_linearVelocity.y; + var wA = bodyA.m_angularVelocity; + var wB = bodyB.m_angularVelocity; + b2Settings.b2Assert(manifold.m_pointCount > 0); + b2ContactSolver.s_worldManifold.Initialize(manifold, bodyA.m_xf, radiusA, bodyB.m_xf, radiusB); + var normalX = b2ContactSolver.s_worldManifold.m_normal.x; + var normalY = b2ContactSolver.s_worldManifold.m_normal.y; + var cc = this.m_constraints[i]; + cc.bodyA = bodyA; + cc.bodyB = bodyB; + cc.manifold = manifold; + cc.normal.x = normalX; + cc.normal.y = normalY; + cc.pointCount = manifold.m_pointCount; + cc.friction = friction; + cc.restitution = restitution; + cc.localPlaneNormal.x = manifold.m_localPlaneNormal.x; + cc.localPlaneNormal.y = manifold.m_localPlaneNormal.y; + cc.localPoint.x = manifold.m_localPoint.x; + cc.localPoint.y = manifold.m_localPoint.y; + cc.radius = radiusA + radiusB; + cc.type = manifold.m_type; + for(var k = 0;k < cc.pointCount;++k) { + var cp = manifold.m_points[k]; + var ccp = cc.points[k]; + ccp.normalImpulse = cp.m_normalImpulse; + ccp.tangentImpulse = cp.m_tangentImpulse; + ccp.localPoint.SetV(cp.m_localPoint); + var rAX = ccp.rA.x = b2ContactSolver.s_worldManifold.m_points[k].x - bodyA.m_sweep.c.x; + var rAY = ccp.rA.y = b2ContactSolver.s_worldManifold.m_points[k].y - bodyA.m_sweep.c.y; + var rBX = ccp.rB.x = b2ContactSolver.s_worldManifold.m_points[k].x - bodyB.m_sweep.c.x; + var rBY = ccp.rB.y = b2ContactSolver.s_worldManifold.m_points[k].y - bodyB.m_sweep.c.y; + var rnA = rAX * normalY - rAY * normalX; + var rnB = rBX * normalY - rBY * normalX; + rnA *= rnA; + rnB *= rnB; + var kNormal = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rnA + bodyB.m_invI * rnB; + ccp.normalMass = 1 / kNormal; + var kEqualized = bodyA.m_mass * bodyA.m_invMass + bodyB.m_mass * bodyB.m_invMass; + kEqualized += bodyA.m_mass * bodyA.m_invI * rnA + bodyB.m_mass * bodyB.m_invI * rnB; + ccp.equalizedMass = 1 / kEqualized; + var tangentX = normalY; + var tangentY = -normalX; + var rtA = rAX * tangentY - rAY * tangentX; + var rtB = rBX * tangentY - rBY * tangentX; + rtA *= rtA; + rtB *= rtB; + var kTangent = bodyA.m_invMass + bodyB.m_invMass + bodyA.m_invI * rtA + bodyB.m_invI * rtB; + ccp.tangentMass = 1 / kTangent; + ccp.velocityBias = 0; + var tX = vBX + -wB * rBY - vAX - -wA * rAY; + var tY = vBY + wB * rBX - vAY - wA * rAX; + var vRel = cc.normal.x * tX + cc.normal.y * tY; + if(vRel < -b2Settings.b2_velocityThreshold) { + ccp.velocityBias += -cc.restitution * vRel + } + } + if(cc.pointCount == 2) { + var ccp1 = cc.points[0]; + var ccp2 = cc.points[1]; + var invMassA = bodyA.m_invMass; + var invIA = bodyA.m_invI; + var invMassB = bodyB.m_invMass; + var invIB = bodyB.m_invI; + var rn1A = ccp1.rA.x * normalY - ccp1.rA.y * normalX; + var rn1B = ccp1.rB.x * normalY - ccp1.rB.y * normalX; + var rn2A = ccp2.rA.x * normalY - ccp2.rA.y * normalX; + var rn2B = ccp2.rB.x * normalY - ccp2.rB.y * normalX; + var k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B; + var k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B; + var k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B; + var k_maxConditionNumber = 100; + if(k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) { + cc.K.col1.Set(k11, k12); + cc.K.col2.Set(k12, k22); + cc.K.GetInverse(cc.normalMass) + }else { + cc.pointCount = 1 + } + } + } +}; +b2ContactSolver.prototype.InitVelocityConstraints = function(step) { + var tVec; + var tVec2; + var tMat; + for(var i = 0;i < this.m_constraintCount;++i) { + var c = this.m_constraints[i]; + var bodyA = c.bodyA; + var bodyB = c.bodyB; + var invMassA = bodyA.m_invMass; + var invIA = bodyA.m_invI; + var invMassB = bodyB.m_invMass; + var invIB = bodyB.m_invI; + var normalX = c.normal.x; + var normalY = c.normal.y; + var tangentX = normalY; + var tangentY = -normalX; + var tX; + var j = 0; + var tCount = 0; + if(step.warmStarting) { + tCount = c.pointCount; + for(j = 0;j < tCount;++j) { + var ccp = c.points[j]; + ccp.normalImpulse *= step.dtRatio; + ccp.tangentImpulse *= step.dtRatio; + var PX = ccp.normalImpulse * normalX + ccp.tangentImpulse * tangentX; + var PY = ccp.normalImpulse * normalY + ccp.tangentImpulse * tangentY; + bodyA.m_angularVelocity -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); + bodyA.m_linearVelocity.x -= invMassA * PX; + bodyA.m_linearVelocity.y -= invMassA * PY; + bodyB.m_angularVelocity += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); + bodyB.m_linearVelocity.x += invMassB * PX; + bodyB.m_linearVelocity.y += invMassB * PY + } + }else { + tCount = c.pointCount; + for(j = 0;j < tCount;++j) { + var ccp2 = c.points[j]; + ccp2.normalImpulse = 0; + ccp2.tangentImpulse = 0 + } + } + } +}; +b2ContactSolver.prototype.SolveVelocityConstraints = function() { + var j = 0; + var ccp; + var rAX; + var rAY; + var rBX; + var rBY; + var dvX; + var dvY; + var vn; + var vt; + var lambda; + var maxFriction; + var newImpulse; + var PX; + var PY; + var dX; + var dY; + var P1X; + var P1Y; + var P2X; + var P2Y; + var tMat; + var tVec; + for(var i = 0;i < this.m_constraintCount;++i) { + var c = this.m_constraints[i]; + var bodyA = c.bodyA; + var bodyB = c.bodyB; + var wA = bodyA.m_angularVelocity; + var wB = bodyB.m_angularVelocity; + var vA = bodyA.m_linearVelocity; + var vB = bodyB.m_linearVelocity; + var invMassA = bodyA.m_invMass; + var invIA = bodyA.m_invI; + var invMassB = bodyB.m_invMass; + var invIB = bodyB.m_invI; + var normalX = c.normal.x; + var normalY = c.normal.y; + var tangentX = normalY; + var tangentY = -normalX; + var friction = c.friction; + var tX; + for(j = 0;j < c.pointCount;j++) { + ccp = c.points[j]; + dvX = vB.x - wB * ccp.rB.y - vA.x + wA * ccp.rA.y; + dvY = vB.y + wB * ccp.rB.x - vA.y - wA * ccp.rA.x; + vt = dvX * tangentX + dvY * tangentY; + lambda = ccp.tangentMass * -vt; + maxFriction = friction * ccp.normalImpulse; + newImpulse = b2Math.Clamp(ccp.tangentImpulse + lambda, -maxFriction, maxFriction); + lambda = newImpulse - ccp.tangentImpulse; + PX = lambda * tangentX; + PY = lambda * tangentY; + vA.x -= invMassA * PX; + vA.y -= invMassA * PY; + wA -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); + vB.x += invMassB * PX; + vB.y += invMassB * PY; + wB += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); + ccp.tangentImpulse = newImpulse + } + var tCount = c.pointCount; + if(c.pointCount == 1) { + ccp = c.points[0]; + dvX = vB.x + -wB * ccp.rB.y - vA.x - -wA * ccp.rA.y; + dvY = vB.y + wB * ccp.rB.x - vA.y - wA * ccp.rA.x; + vn = dvX * normalX + dvY * normalY; + lambda = -ccp.normalMass * (vn - ccp.velocityBias); + newImpulse = ccp.normalImpulse + lambda; + newImpulse = newImpulse > 0 ? newImpulse : 0; + lambda = newImpulse - ccp.normalImpulse; + PX = lambda * normalX; + PY = lambda * normalY; + vA.x -= invMassA * PX; + vA.y -= invMassA * PY; + wA -= invIA * (ccp.rA.x * PY - ccp.rA.y * PX); + vB.x += invMassB * PX; + vB.y += invMassB * PY; + wB += invIB * (ccp.rB.x * PY - ccp.rB.y * PX); + ccp.normalImpulse = newImpulse + }else { + var cp1 = c.points[0]; + var cp2 = c.points[1]; + var aX = cp1.normalImpulse; + var aY = cp2.normalImpulse; + var dv1X = vB.x - wB * cp1.rB.y - vA.x + wA * cp1.rA.y; + var dv1Y = vB.y + wB * cp1.rB.x - vA.y - wA * cp1.rA.x; + var dv2X = vB.x - wB * cp2.rB.y - vA.x + wA * cp2.rA.y; + var dv2Y = vB.y + wB * cp2.rB.x - vA.y - wA * cp2.rA.x; + var vn1 = dv1X * normalX + dv1Y * normalY; + var vn2 = dv2X * normalX + dv2Y * normalY; + var bX = vn1 - cp1.velocityBias; + var bY = vn2 - cp2.velocityBias; + tMat = c.K; + bX -= tMat.col1.x * aX + tMat.col2.x * aY; + bY -= tMat.col1.y * aX + tMat.col2.y * aY; + var k_errorTol = 0.0010; + for(;;) { + tMat = c.normalMass; + var xX = -(tMat.col1.x * bX + tMat.col2.x * bY); + var xY = -(tMat.col1.y * bX + tMat.col2.y * bY); + if(xX >= 0 && xY >= 0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break + } + xX = -cp1.normalMass * bX; + xY = 0; + vn1 = 0; + vn2 = c.K.col1.y * xX + bY; + if(xX >= 0 && vn2 >= 0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break + } + xX = 0; + xY = -cp2.normalMass * bY; + vn1 = c.K.col2.x * xY + bX; + vn2 = 0; + if(xY >= 0 && vn1 >= 0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break + } + xX = 0; + xY = 0; + vn1 = bX; + vn2 = bY; + if(vn1 >= 0 && vn2 >= 0) { + dX = xX - aX; + dY = xY - aY; + P1X = dX * normalX; + P1Y = dX * normalY; + P2X = dY * normalX; + P2Y = dY * normalY; + vA.x -= invMassA * (P1X + P2X); + vA.y -= invMassA * (P1Y + P2Y); + wA -= invIA * (cp1.rA.x * P1Y - cp1.rA.y * P1X + cp2.rA.x * P2Y - cp2.rA.y * P2X); + vB.x += invMassB * (P1X + P2X); + vB.y += invMassB * (P1Y + P2Y); + wB += invIB * (cp1.rB.x * P1Y - cp1.rB.y * P1X + cp2.rB.x * P2Y - cp2.rB.y * P2X); + cp1.normalImpulse = xX; + cp2.normalImpulse = xY; + break + } + break + } + } + bodyA.m_angularVelocity = wA; + bodyB.m_angularVelocity = wB + } +}; +b2ContactSolver.prototype.FinalizeVelocityConstraints = function() { + for(var i = 0;i < this.m_constraintCount;++i) { + var c = this.m_constraints[i]; + var m = c.manifold; + for(var j = 0;j < c.pointCount;++j) { + var point1 = m.m_points[j]; + var point2 = c.points[j]; + point1.m_normalImpulse = point2.normalImpulse; + point1.m_tangentImpulse = point2.tangentImpulse + } + } +}; +b2ContactSolver.prototype.SolvePositionConstraints = function(baumgarte) { + var minSeparation = 0; + for(var i = 0;i < this.m_constraintCount;i++) { + var c = this.m_constraints[i]; + var bodyA = c.bodyA; + var bodyB = c.bodyB; + var invMassA = bodyA.m_mass * bodyA.m_invMass; + var invIA = bodyA.m_mass * bodyA.m_invI; + var invMassB = bodyB.m_mass * bodyB.m_invMass; + var invIB = bodyB.m_mass * bodyB.m_invI; + b2ContactSolver.s_psm.Initialize(c); + var normal = b2ContactSolver.s_psm.m_normal; + for(var j = 0;j < c.pointCount;j++) { + var ccp = c.points[j]; + var point = b2ContactSolver.s_psm.m_points[j]; + var separation = b2ContactSolver.s_psm.m_separations[j]; + var rAX = point.x - bodyA.m_sweep.c.x; + var rAY = point.y - bodyA.m_sweep.c.y; + var rBX = point.x - bodyB.m_sweep.c.x; + var rBY = point.y - bodyB.m_sweep.c.y; + minSeparation = minSeparation < separation ? minSeparation : separation; + var C = b2Math.Clamp(baumgarte * (separation + b2Settings.b2_linearSlop), -b2Settings.b2_maxLinearCorrection, 0); + var impulse = -ccp.equalizedMass * C; + var PX = impulse * normal.x; + var PY = impulse * normal.y; + bodyA.m_sweep.c.x -= invMassA * PX; + bodyA.m_sweep.c.y -= invMassA * PY; + bodyA.m_sweep.a -= invIA * (rAX * PY - rAY * PX); + bodyA.SynchronizeTransform(); + bodyB.m_sweep.c.x += invMassB * PX; + bodyB.m_sweep.c.y += invMassB * PY; + bodyB.m_sweep.a += invIB * (rBX * PY - rBY * PX); + bodyB.SynchronizeTransform() + } + } + return minSeparation > -1.5 * b2Settings.b2_linearSlop +}; +b2ContactSolver.prototype.m_step = new b2TimeStep; +b2ContactSolver.prototype.m_allocator = null; +b2ContactSolver.prototype.m_constraints = new Array; +b2ContactSolver.prototype.m_constraintCount = 0;var b2Simplex = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Simplex.prototype.__constructor = function() { + this.m_vertices[0] = this.m_v1; + this.m_vertices[1] = this.m_v2; + this.m_vertices[2] = this.m_v3 +}; +b2Simplex.prototype.__varz = function() { + this.m_v1 = new b2SimplexVertex; + this.m_v2 = new b2SimplexVertex; + this.m_v3 = new b2SimplexVertex; + this.m_vertices = new Array(3) +}; +b2Simplex.prototype.ReadCache = function(cache, proxyA, transformA, proxyB, transformB) { + b2Settings.b2Assert(0 <= cache.count && cache.count <= 3); + var wALocal; + var wBLocal; + this.m_count = cache.count; + var vertices = this.m_vertices; + for(var i = 0;i < this.m_count;i++) { + var v = vertices[i]; + v.indexA = cache.indexA[i]; + v.indexB = cache.indexB[i]; + wALocal = proxyA.GetVertex(v.indexA); + wBLocal = proxyB.GetVertex(v.indexB); + v.wA = b2Math.MulX(transformA, wALocal); + v.wB = b2Math.MulX(transformB, wBLocal); + v.w = b2Math.SubtractVV(v.wB, v.wA); + v.a = 0 + } + if(this.m_count > 1) { + var metric1 = cache.metric; + var metric2 = this.GetMetric(); + if(metric2 < 0.5 * metric1 || 2 * metric1 < metric2 || metric2 < Number.MIN_VALUE) { + this.m_count = 0 + } + } + if(this.m_count == 0) { + v = vertices[0]; + v.indexA = 0; + v.indexB = 0; + wALocal = proxyA.GetVertex(0); + wBLocal = proxyB.GetVertex(0); + v.wA = b2Math.MulX(transformA, wALocal); + v.wB = b2Math.MulX(transformB, wBLocal); + v.w = b2Math.SubtractVV(v.wB, v.wA); + this.m_count = 1 + } +}; +b2Simplex.prototype.WriteCache = function(cache) { + cache.metric = this.GetMetric(); + cache.count = parseInt(this.m_count); + var vertices = this.m_vertices; + for(var i = 0;i < this.m_count;i++) { + cache.indexA[i] = parseInt(vertices[i].indexA); + cache.indexB[i] = parseInt(vertices[i].indexB) + } +}; +b2Simplex.prototype.GetSearchDirection = function() { + switch(this.m_count) { + case 1: + return this.m_v1.w.GetNegative(); + case 2: + var e12 = b2Math.SubtractVV(this.m_v2.w, this.m_v1.w); + var sgn = b2Math.CrossVV(e12, this.m_v1.w.GetNegative()); + if(sgn > 0) { + return b2Math.CrossFV(1, e12) + }else { + return b2Math.CrossVF(e12, 1) + } + ; + default: + b2Settings.b2Assert(false); + return new b2Vec2 + } +}; +b2Simplex.prototype.GetClosestPoint = function() { + switch(this.m_count) { + case 0: + b2Settings.b2Assert(false); + return new b2Vec2; + case 1: + return this.m_v1.w; + case 2: + return new b2Vec2(this.m_v1.a * this.m_v1.w.x + this.m_v2.a * this.m_v2.w.x, this.m_v1.a * this.m_v1.w.y + this.m_v2.a * this.m_v2.w.y); + default: + b2Settings.b2Assert(false); + return new b2Vec2 + } +}; +b2Simplex.prototype.GetWitnessPoints = function(pA, pB) { + switch(this.m_count) { + case 0: + b2Settings.b2Assert(false); + break; + case 1: + pA.SetV(this.m_v1.wA); + pB.SetV(this.m_v1.wB); + break; + case 2: + pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x; + pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y; + pB.x = this.m_v1.a * this.m_v1.wB.x + this.m_v2.a * this.m_v2.wB.x; + pB.y = this.m_v1.a * this.m_v1.wB.y + this.m_v2.a * this.m_v2.wB.y; + break; + case 3: + pB.x = pA.x = this.m_v1.a * this.m_v1.wA.x + this.m_v2.a * this.m_v2.wA.x + this.m_v3.a * this.m_v3.wA.x; + pB.y = pA.y = this.m_v1.a * this.m_v1.wA.y + this.m_v2.a * this.m_v2.wA.y + this.m_v3.a * this.m_v3.wA.y; + break; + default: + b2Settings.b2Assert(false); + break + } +}; +b2Simplex.prototype.GetMetric = function() { + switch(this.m_count) { + case 0: + b2Settings.b2Assert(false); + return 0; + case 1: + return 0; + case 2: + return b2Math.SubtractVV(this.m_v1.w, this.m_v2.w).Length(); + case 3: + return b2Math.CrossVV(b2Math.SubtractVV(this.m_v2.w, this.m_v1.w), b2Math.SubtractVV(this.m_v3.w, this.m_v1.w)); + default: + b2Settings.b2Assert(false); + return 0 + } +}; +b2Simplex.prototype.Solve2 = function() { + var w1 = this.m_v1.w; + var w2 = this.m_v2.w; + var e12 = b2Math.SubtractVV(w2, w1); + var d12_2 = -(w1.x * e12.x + w1.y * e12.y); + if(d12_2 <= 0) { + this.m_v1.a = 1; + this.m_count = 1; + return + } + var d12_1 = w2.x * e12.x + w2.y * e12.y; + if(d12_1 <= 0) { + this.m_v2.a = 1; + this.m_count = 1; + this.m_v1.Set(this.m_v2); + return + } + var inv_d12 = 1 / (d12_1 + d12_2); + this.m_v1.a = d12_1 * inv_d12; + this.m_v2.a = d12_2 * inv_d12; + this.m_count = 2 +}; +b2Simplex.prototype.Solve3 = function() { + var w1 = this.m_v1.w; + var w2 = this.m_v2.w; + var w3 = this.m_v3.w; + var e12 = b2Math.SubtractVV(w2, w1); + var w1e12 = b2Math.Dot(w1, e12); + var w2e12 = b2Math.Dot(w2, e12); + var d12_1 = w2e12; + var d12_2 = -w1e12; + var e13 = b2Math.SubtractVV(w3, w1); + var w1e13 = b2Math.Dot(w1, e13); + var w3e13 = b2Math.Dot(w3, e13); + var d13_1 = w3e13; + var d13_2 = -w1e13; + var e23 = b2Math.SubtractVV(w3, w2); + var w2e23 = b2Math.Dot(w2, e23); + var w3e23 = b2Math.Dot(w3, e23); + var d23_1 = w3e23; + var d23_2 = -w2e23; + var n123 = b2Math.CrossVV(e12, e13); + var d123_1 = n123 * b2Math.CrossVV(w2, w3); + var d123_2 = n123 * b2Math.CrossVV(w3, w1); + var d123_3 = n123 * b2Math.CrossVV(w1, w2); + if(d12_2 <= 0 && d13_2 <= 0) { + this.m_v1.a = 1; + this.m_count = 1; + return + } + if(d12_1 > 0 && d12_2 > 0 && d123_3 <= 0) { + var inv_d12 = 1 / (d12_1 + d12_2); + this.m_v1.a = d12_1 * inv_d12; + this.m_v2.a = d12_2 * inv_d12; + this.m_count = 2; + return + } + if(d13_1 > 0 && d13_2 > 0 && d123_2 <= 0) { + var inv_d13 = 1 / (d13_1 + d13_2); + this.m_v1.a = d13_1 * inv_d13; + this.m_v3.a = d13_2 * inv_d13; + this.m_count = 2; + this.m_v2.Set(this.m_v3); + return + } + if(d12_1 <= 0 && d23_2 <= 0) { + this.m_v2.a = 1; + this.m_count = 1; + this.m_v1.Set(this.m_v2); + return + } + if(d13_1 <= 0 && d23_1 <= 0) { + this.m_v3.a = 1; + this.m_count = 1; + this.m_v1.Set(this.m_v3); + return + } + if(d23_1 > 0 && d23_2 > 0 && d123_1 <= 0) { + var inv_d23 = 1 / (d23_1 + d23_2); + this.m_v2.a = d23_1 * inv_d23; + this.m_v3.a = d23_2 * inv_d23; + this.m_count = 2; + this.m_v1.Set(this.m_v3); + return + } + var inv_d123 = 1 / (d123_1 + d123_2 + d123_3); + this.m_v1.a = d123_1 * inv_d123; + this.m_v2.a = d123_2 * inv_d123; + this.m_v3.a = d123_3 * inv_d123; + this.m_count = 3 +}; +b2Simplex.prototype.m_v1 = new b2SimplexVertex; +b2Simplex.prototype.m_v2 = new b2SimplexVertex; +b2Simplex.prototype.m_v3 = new b2SimplexVertex; +b2Simplex.prototype.m_vertices = new Array(3); +b2Simplex.prototype.m_count = 0;var b2WeldJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2WeldJoint.prototype, b2Joint.prototype); +b2WeldJoint.prototype._super = b2Joint.prototype; +b2WeldJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + this.m_localAnchorA.SetV(def.localAnchorA); + this.m_localAnchorB.SetV(def.localAnchorB); + this.m_referenceAngle = def.referenceAngle; + this.m_impulse.SetZero(); + this.m_mass = new b2Mat33 +}; +b2WeldJoint.prototype.__varz = function() { + this.m_localAnchorA = new b2Vec2; + this.m_localAnchorB = new b2Vec2; + this.m_impulse = new b2Vec3; + this.m_mass = new b2Mat33 +}; +b2WeldJoint.prototype.InitVelocityConstraints = function(step) { + var tMat; + var tX; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rAX + tMat.col2.x * rAY; + rAY = tMat.col1.y * rAX + tMat.col2.y * rAY; + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rBX + tMat.col2.x * rBY; + rBY = tMat.col1.y * rBX + tMat.col2.y * rBY; + rBX = tX; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + this.m_mass.col1.x = mA + mB + rAY * rAY * iA + rBY * rBY * iB; + this.m_mass.col2.x = -rAY * rAX * iA - rBY * rBX * iB; + this.m_mass.col3.x = -rAY * iA - rBY * iB; + this.m_mass.col1.y = this.m_mass.col2.x; + this.m_mass.col2.y = mA + mB + rAX * rAX * iA + rBX * rBX * iB; + this.m_mass.col3.y = rAX * iA + rBX * iB; + this.m_mass.col1.z = this.m_mass.col3.x; + this.m_mass.col2.z = this.m_mass.col3.y; + this.m_mass.col3.z = iA + iB; + if(step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_impulse.z *= step.dtRatio; + bA.m_linearVelocity.x -= mA * this.m_impulse.x; + bA.m_linearVelocity.y -= mA * this.m_impulse.y; + bA.m_angularVelocity -= iA * (rAX * this.m_impulse.y - rAY * this.m_impulse.x + this.m_impulse.z); + bB.m_linearVelocity.x += mB * this.m_impulse.x; + bB.m_linearVelocity.y += mB * this.m_impulse.y; + bB.m_angularVelocity += iB * (rBX * this.m_impulse.y - rBY * this.m_impulse.x + this.m_impulse.z) + }else { + this.m_impulse.SetZero() + } +}; +b2WeldJoint.prototype.SolveVelocityConstraints = function(step) { + var tMat; + var tX; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var vA = bA.m_linearVelocity; + var wA = bA.m_angularVelocity; + var vB = bB.m_linearVelocity; + var wB = bB.m_angularVelocity; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rAX + tMat.col2.x * rAY; + rAY = tMat.col1.y * rAX + tMat.col2.y * rAY; + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rBX + tMat.col2.x * rBY; + rBY = tMat.col1.y * rBX + tMat.col2.y * rBY; + rBX = tX; + var Cdot1X = vB.x - wB * rBY - vA.x + wA * rAY; + var Cdot1Y = vB.y + wB * rBX - vA.y - wA * rAX; + var Cdot2 = wB - wA; + var impulse = new b2Vec3; + this.m_mass.Solve33(impulse, -Cdot1X, -Cdot1Y, -Cdot2); + this.m_impulse.Add(impulse); + vA.x -= mA * impulse.x; + vA.y -= mA * impulse.y; + wA -= iA * (rAX * impulse.y - rAY * impulse.x + impulse.z); + vB.x += mB * impulse.x; + vB.y += mB * impulse.y; + wB += iB * (rBX * impulse.y - rBY * impulse.x + impulse.z); + bA.m_angularVelocity = wA; + bB.m_angularVelocity = wB +}; +b2WeldJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var tMat; + var tX; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rAX + tMat.col2.x * rAY; + rAY = tMat.col1.y * rAX + tMat.col2.y * rAY; + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rBX + tMat.col2.x * rBY; + rBY = tMat.col1.y * rBX + tMat.col2.y * rBY; + rBX = tX; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + var C1X = bB.m_sweep.c.x + rBX - bA.m_sweep.c.x - rAX; + var C1Y = bB.m_sweep.c.y + rBY - bA.m_sweep.c.y - rAY; + var C2 = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; + var k_allowedStretch = 10 * b2Settings.b2_linearSlop; + var positionError = Math.sqrt(C1X * C1X + C1Y * C1Y); + var angularError = b2Math.Abs(C2); + if(positionError > k_allowedStretch) { + iA *= 1; + iB *= 1 + } + this.m_mass.col1.x = mA + mB + rAY * rAY * iA + rBY * rBY * iB; + this.m_mass.col2.x = -rAY * rAX * iA - rBY * rBX * iB; + this.m_mass.col3.x = -rAY * iA - rBY * iB; + this.m_mass.col1.y = this.m_mass.col2.x; + this.m_mass.col2.y = mA + mB + rAX * rAX * iA + rBX * rBX * iB; + this.m_mass.col3.y = rAX * iA + rBX * iB; + this.m_mass.col1.z = this.m_mass.col3.x; + this.m_mass.col2.z = this.m_mass.col3.y; + this.m_mass.col3.z = iA + iB; + var impulse = new b2Vec3; + this.m_mass.Solve33(impulse, -C1X, -C1Y, -C2); + bA.m_sweep.c.x -= mA * impulse.x; + bA.m_sweep.c.y -= mA * impulse.y; + bA.m_sweep.a -= iA * (rAX * impulse.y - rAY * impulse.x + impulse.z); + bB.m_sweep.c.x += mB * impulse.x; + bB.m_sweep.c.y += mB * impulse.y; + bB.m_sweep.a += iB * (rBX * impulse.y - rBY * impulse.x + impulse.z); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop +}; +b2WeldJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchorA) +}; +b2WeldJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchorB) +}; +b2WeldJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y) +}; +b2WeldJoint.prototype.GetReactionTorque = function(inv_dt) { + return inv_dt * this.m_impulse.z +}; +b2WeldJoint.prototype.m_localAnchorA = new b2Vec2; +b2WeldJoint.prototype.m_localAnchorB = new b2Vec2; +b2WeldJoint.prototype.m_referenceAngle = null; +b2WeldJoint.prototype.m_impulse = new b2Vec3; +b2WeldJoint.prototype.m_mass = new b2Mat33;var b2Math = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Math.prototype.__constructor = function() { +}; +b2Math.prototype.__varz = function() { +}; +b2Math.IsValid = function(x) { + return isFinite(x) +}; +b2Math.Dot = function(a, b) { + return a.x * b.x + a.y * b.y +}; +b2Math.CrossVV = function(a, b) { + return a.x * b.y - a.y * b.x +}; +b2Math.CrossVF = function(a, s) { + var v = new b2Vec2(s * a.y, -s * a.x); + return v +}; +b2Math.CrossFV = function(s, a) { + var v = new b2Vec2(-s * a.y, s * a.x); + return v +}; +b2Math.MulMV = function(A, v) { + var u = new b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y); + return u +}; +b2Math.MulTMV = function(A, v) { + var u = new b2Vec2(b2Math.Dot(v, A.col1), b2Math.Dot(v, A.col2)); + return u +}; +b2Math.MulX = function(T, v) { + var a = b2Math.MulMV(T.R, v); + a.x += T.position.x; + a.y += T.position.y; + return a +}; +b2Math.MulXT = function(T, v) { + var a = b2Math.SubtractVV(v, T.position); + var tX = a.x * T.R.col1.x + a.y * T.R.col1.y; + a.y = a.x * T.R.col2.x + a.y * T.R.col2.y; + a.x = tX; + return a +}; +b2Math.AddVV = function(a, b) { + var v = new b2Vec2(a.x + b.x, a.y + b.y); + return v +}; +b2Math.SubtractVV = function(a, b) { + var v = new b2Vec2(a.x - b.x, a.y - b.y); + return v +}; +b2Math.Distance = function(a, b) { + var cX = a.x - b.x; + var cY = a.y - b.y; + return Math.sqrt(cX * cX + cY * cY) +}; +b2Math.DistanceSquared = function(a, b) { + var cX = a.x - b.x; + var cY = a.y - b.y; + return cX * cX + cY * cY +}; +b2Math.MulFV = function(s, a) { + var v = new b2Vec2(s * a.x, s * a.y); + return v +}; +b2Math.AddMM = function(A, B) { + var C = b2Mat22.FromVV(b2Math.AddVV(A.col1, B.col1), b2Math.AddVV(A.col2, B.col2)); + return C +}; +b2Math.MulMM = function(A, B) { + var C = b2Mat22.FromVV(b2Math.MulMV(A, B.col1), b2Math.MulMV(A, B.col2)); + return C +}; +b2Math.MulTMM = function(A, B) { + var c1 = new b2Vec2(b2Math.Dot(A.col1, B.col1), b2Math.Dot(A.col2, B.col1)); + var c2 = new b2Vec2(b2Math.Dot(A.col1, B.col2), b2Math.Dot(A.col2, B.col2)); + var C = b2Mat22.FromVV(c1, c2); + return C +}; +b2Math.Abs = function(a) { + return a > 0 ? a : -a +}; +b2Math.AbsV = function(a) { + var b = new b2Vec2(b2Math.Abs(a.x), b2Math.Abs(a.y)); + return b +}; +b2Math.AbsM = function(A) { + var B = b2Mat22.FromVV(b2Math.AbsV(A.col1), b2Math.AbsV(A.col2)); + return B +}; +b2Math.Min = function(a, b) { + return a < b ? a : b +}; +b2Math.MinV = function(a, b) { + var c = new b2Vec2(b2Math.Min(a.x, b.x), b2Math.Min(a.y, b.y)); + return c +}; +b2Math.Max = function(a, b) { + return a > b ? a : b +}; +b2Math.MaxV = function(a, b) { + var c = new b2Vec2(b2Math.Max(a.x, b.x), b2Math.Max(a.y, b.y)); + return c +}; +b2Math.Clamp = function(a, low, high) { + return a < low ? low : a > high ? high : a +}; +b2Math.ClampV = function(a, low, high) { + return b2Math.MaxV(low, b2Math.MinV(a, high)) +}; +b2Math.Swap = function(a, b) { + var tmp = a[0]; + a[0] = b[0]; + b[0] = tmp +}; +b2Math.Random = function() { + return Math.random() * 2 - 1 +}; +b2Math.RandomRange = function(lo, hi) { + var r = Math.random(); + r = (hi - lo) * r + lo; + return r +}; +b2Math.NextPowerOfTwo = function(x) { + x |= x >> 1 & 2147483647; + x |= x >> 2 & 1073741823; + x |= x >> 4 & 268435455; + x |= x >> 8 & 16777215; + x |= x >> 16 & 65535; + return x + 1 +}; +b2Math.IsPowerOfTwo = function(x) { + var result = x > 0 && (x & x - 1) == 0; + return result +}; +b2Math.b2Vec2_zero = new b2Vec2(0, 0); +b2Math.b2Mat22_identity = b2Mat22.FromVV(new b2Vec2(1, 0), new b2Vec2(0, 1)); +b2Math.b2Transform_identity = new b2Transform(b2Math.b2Vec2_zero, b2Math.b2Mat22_identity);var b2PulleyJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PulleyJoint.prototype, b2Joint.prototype); +b2PulleyJoint.prototype._super = b2Joint.prototype; +b2PulleyJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + var tMat; + var tX; + var tY; + this.m_ground = this.m_bodyA.m_world.m_groundBody; + this.m_groundAnchor1.x = def.groundAnchorA.x - this.m_ground.m_xf.position.x; + this.m_groundAnchor1.y = def.groundAnchorA.y - this.m_ground.m_xf.position.y; + this.m_groundAnchor2.x = def.groundAnchorB.x - this.m_ground.m_xf.position.x; + this.m_groundAnchor2.y = def.groundAnchorB.y - this.m_ground.m_xf.position.y; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_ratio = def.ratio; + this.m_constant = def.lengthA + this.m_ratio * def.lengthB; + this.m_maxLength1 = b2Math.Min(def.maxLengthA, this.m_constant - this.m_ratio * b2PulleyJoint.b2_minPulleyLength); + this.m_maxLength2 = b2Math.Min(def.maxLengthB, (this.m_constant - b2PulleyJoint.b2_minPulleyLength) / this.m_ratio); + this.m_impulse = 0; + this.m_limitImpulse1 = 0; + this.m_limitImpulse2 = 0 +}; +b2PulleyJoint.prototype.__varz = function() { + this.m_groundAnchor1 = new b2Vec2; + this.m_groundAnchor2 = new b2Vec2; + this.m_localAnchor1 = new b2Vec2; + this.m_localAnchor2 = new b2Vec2; + this.m_u1 = new b2Vec2; + this.m_u2 = new b2Vec2 +}; +b2PulleyJoint.b2_minPulleyLength = 2; +b2PulleyJoint.prototype.InitVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var p1X = bA.m_sweep.c.x + r1X; + var p1Y = bA.m_sweep.c.y + r1Y; + var p2X = bB.m_sweep.c.x + r2X; + var p2Y = bB.m_sweep.c.y + r2Y; + var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + var length1 = this.m_u1.Length(); + var length2 = this.m_u2.Length(); + if(length1 > b2Settings.b2_linearSlop) { + this.m_u1.Multiply(1 / length1) + }else { + this.m_u1.SetZero() + } + if(length2 > b2Settings.b2_linearSlop) { + this.m_u2.Multiply(1 / length2) + }else { + this.m_u2.SetZero() + } + var C = this.m_constant - length1 - this.m_ratio * length2; + if(C > 0) { + this.m_state = b2Joint.e_inactiveLimit; + this.m_impulse = 0 + }else { + this.m_state = b2Joint.e_atUpperLimit + } + if(length1 < this.m_maxLength1) { + this.m_limitState1 = b2Joint.e_inactiveLimit; + this.m_limitImpulse1 = 0 + }else { + this.m_limitState1 = b2Joint.e_atUpperLimit + } + if(length2 < this.m_maxLength2) { + this.m_limitState2 = b2Joint.e_inactiveLimit; + this.m_limitImpulse2 = 0 + }else { + this.m_limitState2 = b2Joint.e_atUpperLimit + } + var cr1u1 = r1X * this.m_u1.y - r1Y * this.m_u1.x; + var cr2u2 = r2X * this.m_u2.y - r2Y * this.m_u2.x; + this.m_limitMass1 = bA.m_invMass + bA.m_invI * cr1u1 * cr1u1; + this.m_limitMass2 = bB.m_invMass + bB.m_invI * cr2u2 * cr2u2; + this.m_pulleyMass = this.m_limitMass1 + this.m_ratio * this.m_ratio * this.m_limitMass2; + this.m_limitMass1 = 1 / this.m_limitMass1; + this.m_limitMass2 = 1 / this.m_limitMass2; + this.m_pulleyMass = 1 / this.m_pulleyMass; + if(step.warmStarting) { + this.m_impulse *= step.dtRatio; + this.m_limitImpulse1 *= step.dtRatio; + this.m_limitImpulse2 *= step.dtRatio; + var P1X = (-this.m_impulse - this.m_limitImpulse1) * this.m_u1.x; + var P1Y = (-this.m_impulse - this.m_limitImpulse1) * this.m_u1.y; + var P2X = (-this.m_ratio * this.m_impulse - this.m_limitImpulse2) * this.m_u2.x; + var P2Y = (-this.m_ratio * this.m_impulse - this.m_limitImpulse2) * this.m_u2.y; + bA.m_linearVelocity.x += bA.m_invMass * P1X; + bA.m_linearVelocity.y += bA.m_invMass * P1Y; + bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); + bB.m_linearVelocity.x += bB.m_invMass * P2X; + bB.m_linearVelocity.y += bB.m_invMass * P2Y; + bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X) + }else { + this.m_impulse = 0; + this.m_limitImpulse1 = 0; + this.m_limitImpulse2 = 0 + } +}; +b2PulleyJoint.prototype.SolveVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var v1X; + var v1Y; + var v2X; + var v2Y; + var P1X; + var P1Y; + var P2X; + var P2Y; + var Cdot; + var impulse; + var oldImpulse; + if(this.m_state == b2Joint.e_atUpperLimit) { + v1X = bA.m_linearVelocity.x + -bA.m_angularVelocity * r1Y; + v1Y = bA.m_linearVelocity.y + bA.m_angularVelocity * r1X; + v2X = bB.m_linearVelocity.x + -bB.m_angularVelocity * r2Y; + v2Y = bB.m_linearVelocity.y + bB.m_angularVelocity * r2X; + Cdot = -(this.m_u1.x * v1X + this.m_u1.y * v1Y) - this.m_ratio * (this.m_u2.x * v2X + this.m_u2.y * v2Y); + impulse = this.m_pulleyMass * -Cdot; + oldImpulse = this.m_impulse; + this.m_impulse = b2Math.Max(0, this.m_impulse + impulse); + impulse = this.m_impulse - oldImpulse; + P1X = -impulse * this.m_u1.x; + P1Y = -impulse * this.m_u1.y; + P2X = -this.m_ratio * impulse * this.m_u2.x; + P2Y = -this.m_ratio * impulse * this.m_u2.y; + bA.m_linearVelocity.x += bA.m_invMass * P1X; + bA.m_linearVelocity.y += bA.m_invMass * P1Y; + bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X); + bB.m_linearVelocity.x += bB.m_invMass * P2X; + bB.m_linearVelocity.y += bB.m_invMass * P2Y; + bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X) + } + if(this.m_limitState1 == b2Joint.e_atUpperLimit) { + v1X = bA.m_linearVelocity.x + -bA.m_angularVelocity * r1Y; + v1Y = bA.m_linearVelocity.y + bA.m_angularVelocity * r1X; + Cdot = -(this.m_u1.x * v1X + this.m_u1.y * v1Y); + impulse = -this.m_limitMass1 * Cdot; + oldImpulse = this.m_limitImpulse1; + this.m_limitImpulse1 = b2Math.Max(0, this.m_limitImpulse1 + impulse); + impulse = this.m_limitImpulse1 - oldImpulse; + P1X = -impulse * this.m_u1.x; + P1Y = -impulse * this.m_u1.y; + bA.m_linearVelocity.x += bA.m_invMass * P1X; + bA.m_linearVelocity.y += bA.m_invMass * P1Y; + bA.m_angularVelocity += bA.m_invI * (r1X * P1Y - r1Y * P1X) + } + if(this.m_limitState2 == b2Joint.e_atUpperLimit) { + v2X = bB.m_linearVelocity.x + -bB.m_angularVelocity * r2Y; + v2Y = bB.m_linearVelocity.y + bB.m_angularVelocity * r2X; + Cdot = -(this.m_u2.x * v2X + this.m_u2.y * v2Y); + impulse = -this.m_limitMass2 * Cdot; + oldImpulse = this.m_limitImpulse2; + this.m_limitImpulse2 = b2Math.Max(0, this.m_limitImpulse2 + impulse); + impulse = this.m_limitImpulse2 - oldImpulse; + P2X = -impulse * this.m_u2.x; + P2Y = -impulse * this.m_u2.y; + bB.m_linearVelocity.x += bB.m_invMass * P2X; + bB.m_linearVelocity.y += bB.m_invMass * P2Y; + bB.m_angularVelocity += bB.m_invI * (r2X * P2Y - r2Y * P2X) + } +}; +b2PulleyJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var s1X = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var s1Y = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + var s2X = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var s2Y = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + var r1X; + var r1Y; + var r2X; + var r2Y; + var p1X; + var p1Y; + var p2X; + var p2Y; + var length1; + var length2; + var C; + var impulse; + var oldImpulse; + var oldLimitPositionImpulse; + var tX; + var linearError = 0; + if(this.m_state == b2Joint.e_atUpperLimit) { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + p1X = bA.m_sweep.c.x + r1X; + p1Y = bA.m_sweep.c.y + r1Y; + p2X = bB.m_sweep.c.x + r2X; + p2Y = bB.m_sweep.c.y + r2Y; + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + length1 = this.m_u1.Length(); + length2 = this.m_u2.Length(); + if(length1 > b2Settings.b2_linearSlop) { + this.m_u1.Multiply(1 / length1) + }else { + this.m_u1.SetZero() + } + if(length2 > b2Settings.b2_linearSlop) { + this.m_u2.Multiply(1 / length2) + }else { + this.m_u2.SetZero() + } + C = this.m_constant - length1 - this.m_ratio * length2; + linearError = b2Math.Max(linearError, -C); + C = b2Math.Clamp(C + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0); + impulse = -this.m_pulleyMass * C; + p1X = -impulse * this.m_u1.x; + p1Y = -impulse * this.m_u1.y; + p2X = -this.m_ratio * impulse * this.m_u2.x; + p2Y = -this.m_ratio * impulse * this.m_u2.y; + bA.m_sweep.c.x += bA.m_invMass * p1X; + bA.m_sweep.c.y += bA.m_invMass * p1Y; + bA.m_sweep.a += bA.m_invI * (r1X * p1Y - r1Y * p1X); + bB.m_sweep.c.x += bB.m_invMass * p2X; + bB.m_sweep.c.y += bB.m_invMass * p2Y; + bB.m_sweep.a += bB.m_invI * (r2X * p2Y - r2Y * p2X); + bA.SynchronizeTransform(); + bB.SynchronizeTransform() + } + if(this.m_limitState1 == b2Joint.e_atUpperLimit) { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + p1X = bA.m_sweep.c.x + r1X; + p1Y = bA.m_sweep.c.y + r1Y; + this.m_u1.Set(p1X - s1X, p1Y - s1Y); + length1 = this.m_u1.Length(); + if(length1 > b2Settings.b2_linearSlop) { + this.m_u1.x *= 1 / length1; + this.m_u1.y *= 1 / length1 + }else { + this.m_u1.SetZero() + } + C = this.m_maxLength1 - length1; + linearError = b2Math.Max(linearError, -C); + C = b2Math.Clamp(C + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0); + impulse = -this.m_limitMass1 * C; + p1X = -impulse * this.m_u1.x; + p1Y = -impulse * this.m_u1.y; + bA.m_sweep.c.x += bA.m_invMass * p1X; + bA.m_sweep.c.y += bA.m_invMass * p1Y; + bA.m_sweep.a += bA.m_invI * (r1X * p1Y - r1Y * p1X); + bA.SynchronizeTransform() + } + if(this.m_limitState2 == b2Joint.e_atUpperLimit) { + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + p2X = bB.m_sweep.c.x + r2X; + p2Y = bB.m_sweep.c.y + r2Y; + this.m_u2.Set(p2X - s2X, p2Y - s2Y); + length2 = this.m_u2.Length(); + if(length2 > b2Settings.b2_linearSlop) { + this.m_u2.x *= 1 / length2; + this.m_u2.y *= 1 / length2 + }else { + this.m_u2.SetZero() + } + C = this.m_maxLength2 - length2; + linearError = b2Math.Max(linearError, -C); + C = b2Math.Clamp(C + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0); + impulse = -this.m_limitMass2 * C; + p2X = -impulse * this.m_u2.x; + p2Y = -impulse * this.m_u2.y; + bB.m_sweep.c.x += bB.m_invMass * p2X; + bB.m_sweep.c.y += bB.m_invMass * p2Y; + bB.m_sweep.a += bB.m_invI * (r2X * p2Y - r2Y * p2X); + bB.SynchronizeTransform() + } + return linearError < b2Settings.b2_linearSlop +}; +b2PulleyJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1) +}; +b2PulleyJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2) +}; +b2PulleyJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_impulse * this.m_u2.x, inv_dt * this.m_impulse * this.m_u2.y) +}; +b2PulleyJoint.prototype.GetReactionTorque = function(inv_dt) { + return 0 +}; +b2PulleyJoint.prototype.GetGroundAnchorA = function() { + var a = this.m_ground.m_xf.position.Copy(); + a.Add(this.m_groundAnchor1); + return a +}; +b2PulleyJoint.prototype.GetGroundAnchorB = function() { + var a = this.m_ground.m_xf.position.Copy(); + a.Add(this.m_groundAnchor2); + return a +}; +b2PulleyJoint.prototype.GetLength1 = function() { + var p = this.m_bodyA.GetWorldPoint(this.m_localAnchor1); + var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor1.x; + var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor1.y; + var dX = p.x - sX; + var dY = p.y - sY; + return Math.sqrt(dX * dX + dY * dY) +}; +b2PulleyJoint.prototype.GetLength2 = function() { + var p = this.m_bodyB.GetWorldPoint(this.m_localAnchor2); + var sX = this.m_ground.m_xf.position.x + this.m_groundAnchor2.x; + var sY = this.m_ground.m_xf.position.y + this.m_groundAnchor2.y; + var dX = p.x - sX; + var dY = p.y - sY; + return Math.sqrt(dX * dX + dY * dY) +}; +b2PulleyJoint.prototype.GetRatio = function() { + return this.m_ratio +}; +b2PulleyJoint.prototype.m_ground = null; +b2PulleyJoint.prototype.m_groundAnchor1 = new b2Vec2; +b2PulleyJoint.prototype.m_groundAnchor2 = new b2Vec2; +b2PulleyJoint.prototype.m_localAnchor1 = new b2Vec2; +b2PulleyJoint.prototype.m_localAnchor2 = new b2Vec2; +b2PulleyJoint.prototype.m_u1 = new b2Vec2; +b2PulleyJoint.prototype.m_u2 = new b2Vec2; +b2PulleyJoint.prototype.m_constant = null; +b2PulleyJoint.prototype.m_ratio = null; +b2PulleyJoint.prototype.m_maxLength1 = null; +b2PulleyJoint.prototype.m_maxLength2 = null; +b2PulleyJoint.prototype.m_pulleyMass = null; +b2PulleyJoint.prototype.m_limitMass1 = null; +b2PulleyJoint.prototype.m_limitMass2 = null; +b2PulleyJoint.prototype.m_impulse = null; +b2PulleyJoint.prototype.m_limitImpulse1 = null; +b2PulleyJoint.prototype.m_limitImpulse2 = null; +b2PulleyJoint.prototype.m_state = 0; +b2PulleyJoint.prototype.m_limitState1 = 0; +b2PulleyJoint.prototype.m_limitState2 = 0;var b2PrismaticJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PrismaticJoint.prototype, b2Joint.prototype); +b2PrismaticJoint.prototype._super = b2Joint.prototype; +b2PrismaticJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + var tMat; + var tX; + var tY; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_localXAxis1.SetV(def.localAxisA); + this.m_localYAxis1.x = -this.m_localXAxis1.y; + this.m_localYAxis1.y = this.m_localXAxis1.x; + this.m_refAngle = def.referenceAngle; + this.m_impulse.SetZero(); + this.m_motorMass = 0; + this.m_motorImpulse = 0; + this.m_lowerTranslation = def.lowerTranslation; + this.m_upperTranslation = def.upperTranslation; + this.m_maxMotorForce = def.maxMotorForce; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_axis.SetZero(); + this.m_perp.SetZero() +}; +b2PrismaticJoint.prototype.__varz = function() { + this.m_localAnchor1 = new b2Vec2; + this.m_localAnchor2 = new b2Vec2; + this.m_localXAxis1 = new b2Vec2; + this.m_localYAxis1 = new b2Vec2; + this.m_axis = new b2Vec2; + this.m_perp = new b2Vec2; + this.m_K = new b2Mat33; + this.m_impulse = new b2Vec3 +}; +b2PrismaticJoint.prototype.InitVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX; + this.m_localCenterA.SetV(bA.GetLocalCenter()); + this.m_localCenterB.SetV(bB.GetLocalCenter()); + var xf1 = bA.GetTransform(); + var xf2 = bB.GetTransform(); + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + this.m_invMassA = bA.m_invMass; + this.m_invMassB = bB.m_invMass; + this.m_invIA = bA.m_invI; + this.m_invIB = bB.m_invI; + this.m_axis.SetV(b2Math.MulMV(xf1.R, this.m_localXAxis1)); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + this.m_motorMass = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_a1 * this.m_a1 + this.m_invIB * this.m_a2 * this.m_a2; + if(this.m_motorMass > Number.MIN_VALUE) { + this.m_motorMass = 1 / this.m_motorMass + } + this.m_perp.SetV(b2Math.MulMV(xf1.R, this.m_localYAxis1)); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var m1 = this.m_invMassA; + var m2 = this.m_invMassB; + var i1 = this.m_invIA; + var i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 + i2 * this.m_s2; + this.m_K.col1.z = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = i1 + i2; + this.m_K.col2.z = i1 * this.m_a1 + i2 * this.m_a2; + this.m_K.col3.x = this.m_K.col1.z; + this.m_K.col3.y = this.m_K.col2.z; + this.m_K.col3.z = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + if(this.m_enableLimit) { + var jointTransition = this.m_axis.x * dX + this.m_axis.y * dY; + if(b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2 * b2Settings.b2_linearSlop) { + this.m_limitState = b2Joint.e_equalLimits + }else { + if(jointTransition <= this.m_lowerTranslation) { + if(this.m_limitState != b2Joint.e_atLowerLimit) { + this.m_limitState = b2Joint.e_atLowerLimit; + this.m_impulse.z = 0 + } + }else { + if(jointTransition >= this.m_upperTranslation) { + if(this.m_limitState != b2Joint.e_atUpperLimit) { + this.m_limitState = b2Joint.e_atUpperLimit; + this.m_impulse.z = 0 + } + }else { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_impulse.z = 0 + } + } + } + }else { + this.m_limitState = b2Joint.e_inactiveLimit + } + if(this.m_enableMotor == false) { + this.m_motorImpulse = 0 + } + if(step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_motorImpulse *= step.dtRatio; + var PX = this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.x; + var PY = this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.y; + var L1 = this.m_impulse.x * this.m_s1 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a1; + var L2 = this.m_impulse.x * this.m_s2 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a2; + bA.m_linearVelocity.x -= this.m_invMassA * PX; + bA.m_linearVelocity.y -= this.m_invMassA * PY; + bA.m_angularVelocity -= this.m_invIA * L1; + bB.m_linearVelocity.x += this.m_invMassB * PX; + bB.m_linearVelocity.y += this.m_invMassB * PY; + bB.m_angularVelocity += this.m_invIB * L2 + }else { + this.m_impulse.SetZero(); + this.m_motorImpulse = 0 + } +}; +b2PrismaticJoint.prototype.SolveVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var v1 = bA.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var v2 = bB.m_linearVelocity; + var w2 = bB.m_angularVelocity; + var PX; + var PY; + var L1; + var L2; + if(this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { + var Cdot = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot); + var oldImpulse = this.m_motorImpulse; + var maxImpulse = step.dt * this.m_maxMotorForce; + this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = this.m_motorImpulse - oldImpulse; + PX = impulse * this.m_axis.x; + PY = impulse * this.m_axis.y; + L1 = impulse * this.m_a1; + L2 = impulse * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2 + } + var Cdot1X = this.m_perp.x * (v2.x - v1.x) + this.m_perp.y * (v2.y - v1.y) + this.m_s2 * w2 - this.m_s1 * w1; + var Cdot1Y = w2 - w1; + if(this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + var Cdot2 = this.m_axis.x * (v2.x - v1.x) + this.m_axis.y * (v2.y - v1.y) + this.m_a2 * w2 - this.m_a1 * w1; + var f1 = this.m_impulse.Copy(); + var df = this.m_K.Solve33(new b2Vec3, -Cdot1X, -Cdot1Y, -Cdot2); + this.m_impulse.Add(df); + if(this.m_limitState == b2Joint.e_atLowerLimit) { + this.m_impulse.z = b2Math.Max(this.m_impulse.z, 0) + }else { + if(this.m_limitState == b2Joint.e_atUpperLimit) { + this.m_impulse.z = b2Math.Min(this.m_impulse.z, 0) + } + } + var bX = -Cdot1X - (this.m_impulse.z - f1.z) * this.m_K.col3.x; + var bY = -Cdot1Y - (this.m_impulse.z - f1.z) * this.m_K.col3.y; + var f2r = this.m_K.Solve22(new b2Vec2, bX, bY); + f2r.x += f1.x; + f2r.y += f1.y; + this.m_impulse.x = f2r.x; + this.m_impulse.y = f2r.y; + df.x = this.m_impulse.x - f1.x; + df.y = this.m_impulse.y - f1.y; + df.z = this.m_impulse.z - f1.z; + PX = df.x * this.m_perp.x + df.z * this.m_axis.x; + PY = df.x * this.m_perp.y + df.z * this.m_axis.y; + L1 = df.x * this.m_s1 + df.y + df.z * this.m_a1; + L2 = df.x * this.m_s2 + df.y + df.z * this.m_a2; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2 + }else { + var df2 = this.m_K.Solve22(new b2Vec2, -Cdot1X, -Cdot1Y); + this.m_impulse.x += df2.x; + this.m_impulse.y += df2.y; + PX = df2.x * this.m_perp.x; + PY = df2.x * this.m_perp.y; + L1 = df2.x * this.m_s1 + df2.y; + L2 = df2.x * this.m_s2 + df2.y; + v1.x -= this.m_invMassA * PX; + v1.y -= this.m_invMassA * PY; + w1 -= this.m_invIA * L1; + v2.x += this.m_invMassB * PX; + v2.y += this.m_invMassB * PY; + w2 += this.m_invIB * L2 + } + bA.m_linearVelocity.SetV(v1); + bA.m_angularVelocity = w1; + bB.m_linearVelocity.SetV(v2); + bB.m_angularVelocity = w2 +}; +b2PrismaticJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var limitC; + var oldLimitImpulse; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var c1 = bA.m_sweep.c; + var a1 = bA.m_sweep.a; + var c2 = bB.m_sweep.c; + var a2 = bB.m_sweep.a; + var tMat; + var tX; + var m1; + var m2; + var i1; + var i2; + var linearError = 0; + var angularError = 0; + var active = false; + var C2 = 0; + var R1 = b2Mat22.FromAngle(a1); + var R2 = b2Mat22.FromAngle(a2); + tMat = R1; + var r1X = this.m_localAnchor1.x - this.m_localCenterA.x; + var r1Y = this.m_localAnchor1.y - this.m_localCenterA.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = R2; + var r2X = this.m_localAnchor2.x - this.m_localCenterB.x; + var r2Y = this.m_localAnchor2.y - this.m_localCenterB.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var dX = c2.x + r2X - c1.x - r1X; + var dY = c2.y + r2Y - c1.y - r1Y; + if(this.m_enableLimit) { + this.m_axis = b2Math.MulMV(R1, this.m_localXAxis1); + this.m_a1 = (dX + r1X) * this.m_axis.y - (dY + r1Y) * this.m_axis.x; + this.m_a2 = r2X * this.m_axis.y - r2Y * this.m_axis.x; + var translation = this.m_axis.x * dX + this.m_axis.y * dY; + if(b2Math.Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2 * b2Settings.b2_linearSlop) { + C2 = b2Math.Clamp(translation, -b2Settings.b2_maxLinearCorrection, b2Settings.b2_maxLinearCorrection); + linearError = b2Math.Abs(translation); + active = true + }else { + if(translation <= this.m_lowerTranslation) { + C2 = b2Math.Clamp(translation - this.m_lowerTranslation + b2Settings.b2_linearSlop, -b2Settings.b2_maxLinearCorrection, 0); + linearError = this.m_lowerTranslation - translation; + active = true + }else { + if(translation >= this.m_upperTranslation) { + C2 = b2Math.Clamp(translation - this.m_upperTranslation + b2Settings.b2_linearSlop, 0, b2Settings.b2_maxLinearCorrection); + linearError = translation - this.m_upperTranslation; + active = true + } + } + } + } + this.m_perp = b2Math.MulMV(R1, this.m_localYAxis1); + this.m_s1 = (dX + r1X) * this.m_perp.y - (dY + r1Y) * this.m_perp.x; + this.m_s2 = r2X * this.m_perp.y - r2Y * this.m_perp.x; + var impulse = new b2Vec3; + var C1X = this.m_perp.x * dX + this.m_perp.y * dY; + var C1Y = a2 - a1 - this.m_refAngle; + linearError = b2Math.Max(linearError, b2Math.Abs(C1X)); + angularError = b2Math.Abs(C1Y); + if(active) { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + this.m_K.col1.x = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + this.m_K.col1.y = i1 * this.m_s1 + i2 * this.m_s2; + this.m_K.col1.z = i1 * this.m_s1 * this.m_a1 + i2 * this.m_s2 * this.m_a2; + this.m_K.col2.x = this.m_K.col1.y; + this.m_K.col2.y = i1 + i2; + this.m_K.col2.z = i1 * this.m_a1 + i2 * this.m_a2; + this.m_K.col3.x = this.m_K.col1.z; + this.m_K.col3.y = this.m_K.col2.z; + this.m_K.col3.z = m1 + m2 + i1 * this.m_a1 * this.m_a1 + i2 * this.m_a2 * this.m_a2; + this.m_K.Solve33(impulse, -C1X, -C1Y, -C2) + }else { + m1 = this.m_invMassA; + m2 = this.m_invMassB; + i1 = this.m_invIA; + i2 = this.m_invIB; + var k11 = m1 + m2 + i1 * this.m_s1 * this.m_s1 + i2 * this.m_s2 * this.m_s2; + var k12 = i1 * this.m_s1 + i2 * this.m_s2; + var k22 = i1 + i2; + this.m_K.col1.Set(k11, k12, 0); + this.m_K.col2.Set(k12, k22, 0); + var impulse1 = this.m_K.Solve22(new b2Vec2, -C1X, -C1Y); + impulse.x = impulse1.x; + impulse.y = impulse1.y; + impulse.z = 0 + } + var PX = impulse.x * this.m_perp.x + impulse.z * this.m_axis.x; + var PY = impulse.x * this.m_perp.y + impulse.z * this.m_axis.y; + var L1 = impulse.x * this.m_s1 + impulse.y + impulse.z * this.m_a1; + var L2 = impulse.x * this.m_s2 + impulse.y + impulse.z * this.m_a2; + c1.x -= this.m_invMassA * PX; + c1.y -= this.m_invMassA * PY; + a1 -= this.m_invIA * L1; + c2.x += this.m_invMassB * PX; + c2.y += this.m_invMassB * PY; + a2 += this.m_invIB * L2; + bA.m_sweep.a = a1; + bB.m_sweep.a = a2; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return linearError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop +}; +b2PrismaticJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1) +}; +b2PrismaticJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2) +}; +b2PrismaticJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * (this.m_impulse.x * this.m_perp.x + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.x), inv_dt * (this.m_impulse.x * this.m_perp.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_axis.y)) +}; +b2PrismaticJoint.prototype.GetReactionTorque = function(inv_dt) { + return inv_dt * this.m_impulse.y +}; +b2PrismaticJoint.prototype.GetJointTranslation = function() { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var p1 = bA.GetWorldPoint(this.m_localAnchor1); + var p2 = bB.GetWorldPoint(this.m_localAnchor2); + var dX = p2.x - p1.x; + var dY = p2.y - p1.y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var translation = axis.x * dX + axis.y * dY; + return translation +}; +b2PrismaticJoint.prototype.GetJointSpeed = function() { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var p1X = bA.m_sweep.c.x + r1X; + var p1Y = bA.m_sweep.c.y + r1Y; + var p2X = bB.m_sweep.c.x + r2X; + var p2Y = bB.m_sweep.c.y + r2Y; + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var axis = bA.GetWorldVector(this.m_localXAxis1); + var v1 = bA.m_linearVelocity; + var v2 = bB.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var w2 = bB.m_angularVelocity; + var speed = dX * -w1 * axis.y + dY * w1 * axis.x + (axis.x * (v2.x + -w2 * r2Y - v1.x - -w1 * r1Y) + axis.y * (v2.y + w2 * r2X - v1.y - w1 * r1X)); + return speed +}; +b2PrismaticJoint.prototype.IsLimitEnabled = function() { + return this.m_enableLimit +}; +b2PrismaticJoint.prototype.EnableLimit = function(flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableLimit = flag +}; +b2PrismaticJoint.prototype.GetLowerLimit = function() { + return this.m_lowerTranslation +}; +b2PrismaticJoint.prototype.GetUpperLimit = function() { + return this.m_upperTranslation +}; +b2PrismaticJoint.prototype.SetLimits = function(lower, upper) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_lowerTranslation = lower; + this.m_upperTranslation = upper +}; +b2PrismaticJoint.prototype.IsMotorEnabled = function() { + return this.m_enableMotor +}; +b2PrismaticJoint.prototype.EnableMotor = function(flag) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_enableMotor = flag +}; +b2PrismaticJoint.prototype.SetMotorSpeed = function(speed) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_motorSpeed = speed +}; +b2PrismaticJoint.prototype.GetMotorSpeed = function() { + return this.m_motorSpeed +}; +b2PrismaticJoint.prototype.SetMaxMotorForce = function(force) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_maxMotorForce = force +}; +b2PrismaticJoint.prototype.GetMotorForce = function() { + return this.m_motorImpulse +}; +b2PrismaticJoint.prototype.m_localAnchor1 = new b2Vec2; +b2PrismaticJoint.prototype.m_localAnchor2 = new b2Vec2; +b2PrismaticJoint.prototype.m_localXAxis1 = new b2Vec2; +b2PrismaticJoint.prototype.m_localYAxis1 = new b2Vec2; +b2PrismaticJoint.prototype.m_refAngle = null; +b2PrismaticJoint.prototype.m_axis = new b2Vec2; +b2PrismaticJoint.prototype.m_perp = new b2Vec2; +b2PrismaticJoint.prototype.m_s1 = null; +b2PrismaticJoint.prototype.m_s2 = null; +b2PrismaticJoint.prototype.m_a1 = null; +b2PrismaticJoint.prototype.m_a2 = null; +b2PrismaticJoint.prototype.m_K = new b2Mat33; +b2PrismaticJoint.prototype.m_impulse = new b2Vec3; +b2PrismaticJoint.prototype.m_motorMass = null; +b2PrismaticJoint.prototype.m_motorImpulse = null; +b2PrismaticJoint.prototype.m_lowerTranslation = null; +b2PrismaticJoint.prototype.m_upperTranslation = null; +b2PrismaticJoint.prototype.m_maxMotorForce = null; +b2PrismaticJoint.prototype.m_motorSpeed = null; +b2PrismaticJoint.prototype.m_enableLimit = null; +b2PrismaticJoint.prototype.m_enableMotor = null; +b2PrismaticJoint.prototype.m_limitState = 0;var b2RevoluteJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2RevoluteJoint.prototype, b2Joint.prototype); +b2RevoluteJoint.prototype._super = b2Joint.prototype; +b2RevoluteJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_referenceAngle = def.referenceAngle; + this.m_impulse.SetZero(); + this.m_motorImpulse = 0; + this.m_lowerAngle = def.lowerAngle; + this.m_upperAngle = def.upperAngle; + this.m_maxMotorTorque = def.maxMotorTorque; + this.m_motorSpeed = def.motorSpeed; + this.m_enableLimit = def.enableLimit; + this.m_enableMotor = def.enableMotor; + this.m_limitState = b2Joint.e_inactiveLimit +}; +b2RevoluteJoint.prototype.__varz = function() { + this.K = new b2Mat22; + this.K1 = new b2Mat22; + this.K2 = new b2Mat22; + this.K3 = new b2Mat22; + this.impulse3 = new b2Vec3; + this.impulse2 = new b2Vec2; + this.reduced = new b2Vec2; + this.m_localAnchor1 = new b2Vec2; + this.m_localAnchor2 = new b2Vec2; + this.m_impulse = new b2Vec3; + this.m_mass = new b2Mat33 +}; +b2RevoluteJoint.tImpulse = new b2Vec2; +b2RevoluteJoint.prototype.InitVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX; + if(this.m_enableMotor || this.m_enableLimit) { + } + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var m1 = bA.m_invMass; + var m2 = bB.m_invMass; + var i1 = bA.m_invI; + var i2 = bB.m_invI; + this.m_mass.col1.x = m1 + m2 + r1Y * r1Y * i1 + r2Y * r2Y * i2; + this.m_mass.col2.x = -r1Y * r1X * i1 - r2Y * r2X * i2; + this.m_mass.col3.x = -r1Y * i1 - r2Y * i2; + this.m_mass.col1.y = this.m_mass.col2.x; + this.m_mass.col2.y = m1 + m2 + r1X * r1X * i1 + r2X * r2X * i2; + this.m_mass.col3.y = r1X * i1 + r2X * i2; + this.m_mass.col1.z = this.m_mass.col3.x; + this.m_mass.col2.z = this.m_mass.col3.y; + this.m_mass.col3.z = i1 + i2; + this.m_motorMass = 1 / (i1 + i2); + if(this.m_enableMotor == false) { + this.m_motorImpulse = 0 + } + if(this.m_enableLimit) { + var jointAngle = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; + if(b2Math.Abs(this.m_upperAngle - this.m_lowerAngle) < 2 * b2Settings.b2_angularSlop) { + this.m_limitState = b2Joint.e_equalLimits + }else { + if(jointAngle <= this.m_lowerAngle) { + if(this.m_limitState != b2Joint.e_atLowerLimit) { + this.m_impulse.z = 0 + } + this.m_limitState = b2Joint.e_atLowerLimit + }else { + if(jointAngle >= this.m_upperAngle) { + if(this.m_limitState != b2Joint.e_atUpperLimit) { + this.m_impulse.z = 0 + } + this.m_limitState = b2Joint.e_atUpperLimit + }else { + this.m_limitState = b2Joint.e_inactiveLimit; + this.m_impulse.z = 0 + } + } + } + }else { + this.m_limitState = b2Joint.e_inactiveLimit + } + if(step.warmStarting) { + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + this.m_motorImpulse *= step.dtRatio; + var PX = this.m_impulse.x; + var PY = this.m_impulse.y; + bA.m_linearVelocity.x -= m1 * PX; + bA.m_linearVelocity.y -= m1 * PY; + bA.m_angularVelocity -= i1 * (r1X * PY - r1Y * PX + this.m_motorImpulse + this.m_impulse.z); + bB.m_linearVelocity.x += m2 * PX; + bB.m_linearVelocity.y += m2 * PY; + bB.m_angularVelocity += i2 * (r2X * PY - r2Y * PX + this.m_motorImpulse + this.m_impulse.z) + }else { + this.m_impulse.SetZero(); + this.m_motorImpulse = 0 + } +}; +b2RevoluteJoint.prototype.SolveVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var tMat; + var tX; + var newImpulse; + var r1X; + var r1Y; + var r2X; + var r2Y; + var v1 = bA.m_linearVelocity; + var w1 = bA.m_angularVelocity; + var v2 = bB.m_linearVelocity; + var w2 = bB.m_angularVelocity; + var m1 = bA.m_invMass; + var m2 = bB.m_invMass; + var i1 = bA.m_invI; + var i2 = bB.m_invI; + if(this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) { + var Cdot = w2 - w1 - this.m_motorSpeed; + var impulse = this.m_motorMass * -Cdot; + var oldImpulse = this.m_motorImpulse; + var maxImpulse = step.dt * this.m_maxMotorTorque; + this.m_motorImpulse = b2Math.Clamp(this.m_motorImpulse + impulse, -maxImpulse, maxImpulse); + impulse = this.m_motorImpulse - oldImpulse; + w1 -= i1 * impulse; + w2 += i2 * impulse + } + if(this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var Cdot1X = v2.x + -w2 * r2Y - v1.x - -w1 * r1Y; + var Cdot1Y = v2.y + w2 * r2X - v1.y - w1 * r1X; + var Cdot2 = w2 - w1; + this.m_mass.Solve33(this.impulse3, -Cdot1X, -Cdot1Y, -Cdot2); + if(this.m_limitState == b2Joint.e_equalLimits) { + this.m_impulse.Add(this.impulse3) + }else { + if(this.m_limitState == b2Joint.e_atLowerLimit) { + newImpulse = this.m_impulse.z + this.impulse3.z; + if(newImpulse < 0) { + this.m_mass.Solve22(this.reduced, -Cdot1X, -Cdot1Y); + this.impulse3.x = this.reduced.x; + this.impulse3.y = this.reduced.y; + this.impulse3.z = -this.m_impulse.z; + this.m_impulse.x += this.reduced.x; + this.m_impulse.y += this.reduced.y; + this.m_impulse.z = 0 + } + }else { + if(this.m_limitState == b2Joint.e_atUpperLimit) { + newImpulse = this.m_impulse.z + this.impulse3.z; + if(newImpulse > 0) { + this.m_mass.Solve22(this.reduced, -Cdot1X, -Cdot1Y); + this.impulse3.x = this.reduced.x; + this.impulse3.y = this.reduced.y; + this.impulse3.z = -this.m_impulse.z; + this.m_impulse.x += this.reduced.x; + this.m_impulse.y += this.reduced.y; + this.m_impulse.z = 0 + } + } + } + } + v1.x -= m1 * this.impulse3.x; + v1.y -= m1 * this.impulse3.y; + w1 -= i1 * (r1X * this.impulse3.y - r1Y * this.impulse3.x + this.impulse3.z); + v2.x += m2 * this.impulse3.x; + v2.y += m2 * this.impulse3.y; + w2 += i2 * (r2X * this.impulse3.y - r2Y * this.impulse3.x + this.impulse3.z) + }else { + tMat = bA.m_xf.R; + r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var CdotX = v2.x + -w2 * r2Y - v1.x - -w1 * r1Y; + var CdotY = v2.y + w2 * r2X - v1.y - w1 * r1X; + this.m_mass.Solve22(this.impulse2, -CdotX, -CdotY); + this.m_impulse.x += this.impulse2.x; + this.m_impulse.y += this.impulse2.y; + v1.x -= m1 * this.impulse2.x; + v1.y -= m1 * this.impulse2.y; + w1 -= i1 * (r1X * this.impulse2.y - r1Y * this.impulse2.x); + v2.x += m2 * this.impulse2.x; + v2.y += m2 * this.impulse2.y; + w2 += i2 * (r2X * this.impulse2.y - r2Y * this.impulse2.x) + } + bA.m_linearVelocity.SetV(v1); + bA.m_angularVelocity = w1; + bB.m_linearVelocity.SetV(v2); + bB.m_angularVelocity = w2 +}; +b2RevoluteJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var oldLimitImpulse; + var C; + var tMat; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var angularError = 0; + var positionError = 0; + var tX; + var impulseX; + var impulseY; + if(this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) { + var angle = bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle; + var limitImpulse = 0; + if(this.m_limitState == b2Joint.e_equalLimits) { + C = b2Math.Clamp(angle - this.m_lowerAngle, -b2Settings.b2_maxAngularCorrection, b2Settings.b2_maxAngularCorrection); + limitImpulse = -this.m_motorMass * C; + angularError = b2Math.Abs(C) + }else { + if(this.m_limitState == b2Joint.e_atLowerLimit) { + C = angle - this.m_lowerAngle; + angularError = -C; + C = b2Math.Clamp(C + b2Settings.b2_angularSlop, -b2Settings.b2_maxAngularCorrection, 0); + limitImpulse = -this.m_motorMass * C + }else { + if(this.m_limitState == b2Joint.e_atUpperLimit) { + C = angle - this.m_upperAngle; + angularError = C; + C = b2Math.Clamp(C - b2Settings.b2_angularSlop, 0, b2Settings.b2_maxAngularCorrection); + limitImpulse = -this.m_motorMass * C + } + } + } + bA.m_sweep.a -= bA.m_invI * limitImpulse; + bB.m_sweep.a += bB.m_invI * limitImpulse; + bA.SynchronizeTransform(); + bB.SynchronizeTransform() + } + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var CX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var CY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + var CLengthSquared = CX * CX + CY * CY; + var CLength = Math.sqrt(CLengthSquared); + positionError = CLength; + var invMass1 = bA.m_invMass; + var invMass2 = bB.m_invMass; + var invI1 = bA.m_invI; + var invI2 = bB.m_invI; + var k_allowedStretch = 10 * b2Settings.b2_linearSlop; + if(CLengthSquared > k_allowedStretch * k_allowedStretch) { + var uX = CX / CLength; + var uY = CY / CLength; + var k = invMass1 + invMass2; + var m = 1 / k; + impulseX = m * -CX; + impulseY = m * -CY; + var k_beta = 0.5; + bA.m_sweep.c.x -= k_beta * invMass1 * impulseX; + bA.m_sweep.c.y -= k_beta * invMass1 * impulseY; + bB.m_sweep.c.x += k_beta * invMass2 * impulseX; + bB.m_sweep.c.y += k_beta * invMass2 * impulseY; + CX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + CY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y + } + this.K1.col1.x = invMass1 + invMass2; + this.K1.col2.x = 0; + this.K1.col1.y = 0; + this.K1.col2.y = invMass1 + invMass2; + this.K2.col1.x = invI1 * r1Y * r1Y; + this.K2.col2.x = -invI1 * r1X * r1Y; + this.K2.col1.y = -invI1 * r1X * r1Y; + this.K2.col2.y = invI1 * r1X * r1X; + this.K3.col1.x = invI2 * r2Y * r2Y; + this.K3.col2.x = -invI2 * r2X * r2Y; + this.K3.col1.y = -invI2 * r2X * r2Y; + this.K3.col2.y = invI2 * r2X * r2X; + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.AddM(this.K3); + this.K.Solve(b2RevoluteJoint.tImpulse, -CX, -CY); + impulseX = b2RevoluteJoint.tImpulse.x; + impulseY = b2RevoluteJoint.tImpulse.y; + bA.m_sweep.c.x -= bA.m_invMass * impulseX; + bA.m_sweep.c.y -= bA.m_invMass * impulseY; + bA.m_sweep.a -= bA.m_invI * (r1X * impulseY - r1Y * impulseX); + bB.m_sweep.c.x += bB.m_invMass * impulseX; + bB.m_sweep.c.y += bB.m_invMass * impulseY; + bB.m_sweep.a += bB.m_invI * (r2X * impulseY - r2Y * impulseX); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop +}; +b2RevoluteJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1) +}; +b2RevoluteJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2) +}; +b2RevoluteJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y) +}; +b2RevoluteJoint.prototype.GetReactionTorque = function(inv_dt) { + return inv_dt * this.m_impulse.z +}; +b2RevoluteJoint.prototype.GetJointAngle = function() { + return this.m_bodyB.m_sweep.a - this.m_bodyA.m_sweep.a - this.m_referenceAngle +}; +b2RevoluteJoint.prototype.GetJointSpeed = function() { + return this.m_bodyB.m_angularVelocity - this.m_bodyA.m_angularVelocity +}; +b2RevoluteJoint.prototype.IsLimitEnabled = function() { + return this.m_enableLimit +}; +b2RevoluteJoint.prototype.EnableLimit = function(flag) { + this.m_enableLimit = flag +}; +b2RevoluteJoint.prototype.GetLowerLimit = function() { + return this.m_lowerAngle +}; +b2RevoluteJoint.prototype.GetUpperLimit = function() { + return this.m_upperAngle +}; +b2RevoluteJoint.prototype.SetLimits = function(lower, upper) { + this.m_lowerAngle = lower; + this.m_upperAngle = upper +}; +b2RevoluteJoint.prototype.IsMotorEnabled = function() { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + return this.m_enableMotor +}; +b2RevoluteJoint.prototype.EnableMotor = function(flag) { + this.m_enableMotor = flag +}; +b2RevoluteJoint.prototype.SetMotorSpeed = function(speed) { + this.m_bodyA.SetAwake(true); + this.m_bodyB.SetAwake(true); + this.m_motorSpeed = speed +}; +b2RevoluteJoint.prototype.GetMotorSpeed = function() { + return this.m_motorSpeed +}; +b2RevoluteJoint.prototype.SetMaxMotorTorque = function(torque) { + this.m_maxMotorTorque = torque +}; +b2RevoluteJoint.prototype.GetMotorTorque = function() { + return this.m_maxMotorTorque +}; +b2RevoluteJoint.prototype.K = new b2Mat22; +b2RevoluteJoint.prototype.K1 = new b2Mat22; +b2RevoluteJoint.prototype.K2 = new b2Mat22; +b2RevoluteJoint.prototype.K3 = new b2Mat22; +b2RevoluteJoint.prototype.impulse3 = new b2Vec3; +b2RevoluteJoint.prototype.impulse2 = new b2Vec2; +b2RevoluteJoint.prototype.reduced = new b2Vec2; +b2RevoluteJoint.prototype.m_localAnchor1 = new b2Vec2; +b2RevoluteJoint.prototype.m_localAnchor2 = new b2Vec2; +b2RevoluteJoint.prototype.m_impulse = new b2Vec3; +b2RevoluteJoint.prototype.m_motorImpulse = null; +b2RevoluteJoint.prototype.m_mass = new b2Mat33; +b2RevoluteJoint.prototype.m_motorMass = null; +b2RevoluteJoint.prototype.m_enableMotor = null; +b2RevoluteJoint.prototype.m_maxMotorTorque = null; +b2RevoluteJoint.prototype.m_motorSpeed = null; +b2RevoluteJoint.prototype.m_enableLimit = null; +b2RevoluteJoint.prototype.m_referenceAngle = null; +b2RevoluteJoint.prototype.m_lowerAngle = null; +b2RevoluteJoint.prototype.m_upperAngle = null; +b2RevoluteJoint.prototype.m_limitState = 0;var b2JointDef = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2JointDef.prototype.__constructor = function() { + this.type = b2Joint.e_unknownJoint; + this.userData = null; + this.bodyA = null; + this.bodyB = null; + this.collideConnected = false +}; +b2JointDef.prototype.__varz = function() { +}; +b2JointDef.prototype.type = 0; +b2JointDef.prototype.userData = null; +b2JointDef.prototype.bodyA = null; +b2JointDef.prototype.bodyB = null; +b2JointDef.prototype.collideConnected = null;var b2LineJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2LineJointDef.prototype, b2JointDef.prototype); +b2LineJointDef.prototype._super = b2JointDef.prototype; +b2LineJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_lineJoint; + this.localAxisA.Set(1, 0); + this.enableLimit = false; + this.lowerTranslation = 0; + this.upperTranslation = 0; + this.enableMotor = false; + this.maxMotorForce = 0; + this.motorSpeed = 0 +}; +b2LineJointDef.prototype.__varz = function() { + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2; + this.localAxisA = new b2Vec2 +}; +b2LineJointDef.prototype.Initialize = function(bA, bB, anchor, axis) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA = this.bodyA.GetLocalPoint(anchor); + this.localAnchorB = this.bodyB.GetLocalPoint(anchor); + this.localAxisA = this.bodyA.GetLocalVector(axis) +}; +b2LineJointDef.prototype.localAnchorA = new b2Vec2; +b2LineJointDef.prototype.localAnchorB = new b2Vec2; +b2LineJointDef.prototype.localAxisA = new b2Vec2; +b2LineJointDef.prototype.enableLimit = null; +b2LineJointDef.prototype.lowerTranslation = null; +b2LineJointDef.prototype.upperTranslation = null; +b2LineJointDef.prototype.enableMotor = null; +b2LineJointDef.prototype.maxMotorForce = null; +b2LineJointDef.prototype.motorSpeed = null;var b2DistanceJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2DistanceJoint.prototype, b2Joint.prototype); +b2DistanceJoint.prototype._super = b2Joint.prototype; +b2DistanceJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + var tMat; + var tX; + var tY; + this.m_localAnchor1.SetV(def.localAnchorA); + this.m_localAnchor2.SetV(def.localAnchorB); + this.m_length = def.length; + this.m_frequencyHz = def.frequencyHz; + this.m_dampingRatio = def.dampingRatio; + this.m_impulse = 0; + this.m_gamma = 0; + this.m_bias = 0 +}; +b2DistanceJoint.prototype.__varz = function() { + this.m_localAnchor1 = new b2Vec2; + this.m_localAnchor2 = new b2Vec2; + this.m_u = new b2Vec2 +}; +b2DistanceJoint.prototype.InitVelocityConstraints = function(step) { + var tMat; + var tX; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + this.m_u.x = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + this.m_u.y = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + var length = Math.sqrt(this.m_u.x * this.m_u.x + this.m_u.y * this.m_u.y); + if(length > b2Settings.b2_linearSlop) { + this.m_u.Multiply(1 / length) + }else { + this.m_u.SetZero() + } + var cr1u = r1X * this.m_u.y - r1Y * this.m_u.x; + var cr2u = r2X * this.m_u.y - r2Y * this.m_u.x; + var invMass = bA.m_invMass + bA.m_invI * cr1u * cr1u + bB.m_invMass + bB.m_invI * cr2u * cr2u; + this.m_mass = invMass != 0 ? 1 / invMass : 0; + if(this.m_frequencyHz > 0) { + var C = length - this.m_length; + var omega = 2 * Math.PI * this.m_frequencyHz; + var d = 2 * this.m_mass * this.m_dampingRatio * omega; + var k = this.m_mass * omega * omega; + this.m_gamma = step.dt * (d + step.dt * k); + this.m_gamma = this.m_gamma != 0 ? 1 / this.m_gamma : 0; + this.m_bias = C * step.dt * k * this.m_gamma; + this.m_mass = invMass + this.m_gamma; + this.m_mass = this.m_mass != 0 ? 1 / this.m_mass : 0 + } + if(step.warmStarting) { + this.m_impulse *= step.dtRatio; + var PX = this.m_impulse * this.m_u.x; + var PY = this.m_impulse * this.m_u.y; + bA.m_linearVelocity.x -= bA.m_invMass * PX; + bA.m_linearVelocity.y -= bA.m_invMass * PY; + bA.m_angularVelocity -= bA.m_invI * (r1X * PY - r1Y * PX); + bB.m_linearVelocity.x += bB.m_invMass * PX; + bB.m_linearVelocity.y += bB.m_invMass * PY; + bB.m_angularVelocity += bB.m_invI * (r2X * PY - r2Y * PX) + }else { + this.m_impulse = 0 + } +}; +b2DistanceJoint.prototype.SolveVelocityConstraints = function(step) { + var tMat; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var v1X = bA.m_linearVelocity.x + -bA.m_angularVelocity * r1Y; + var v1Y = bA.m_linearVelocity.y + bA.m_angularVelocity * r1X; + var v2X = bB.m_linearVelocity.x + -bB.m_angularVelocity * r2Y; + var v2Y = bB.m_linearVelocity.y + bB.m_angularVelocity * r2X; + var Cdot = this.m_u.x * (v2X - v1X) + this.m_u.y * (v2Y - v1Y); + var impulse = -this.m_mass * (Cdot + this.m_bias + this.m_gamma * this.m_impulse); + this.m_impulse += impulse; + var PX = impulse * this.m_u.x; + var PY = impulse * this.m_u.y; + bA.m_linearVelocity.x -= bA.m_invMass * PX; + bA.m_linearVelocity.y -= bA.m_invMass * PY; + bA.m_angularVelocity -= bA.m_invI * (r1X * PY - r1Y * PX); + bB.m_linearVelocity.x += bB.m_invMass * PX; + bB.m_linearVelocity.y += bB.m_invMass * PY; + bB.m_angularVelocity += bB.m_invI * (r2X * PY - r2Y * PX) +}; +b2DistanceJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var tMat; + if(this.m_frequencyHz > 0) { + return true + } + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var r1X = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + var r1Y = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + var tX = tMat.col1.x * r1X + tMat.col2.x * r1Y; + r1Y = tMat.col1.y * r1X + tMat.col2.y * r1Y; + r1X = tX; + tMat = bB.m_xf.R; + var r2X = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + var r2Y = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * r2X + tMat.col2.x * r2Y; + r2Y = tMat.col1.y * r2X + tMat.col2.y * r2Y; + r2X = tX; + var dX = bB.m_sweep.c.x + r2X - bA.m_sweep.c.x - r1X; + var dY = bB.m_sweep.c.y + r2Y - bA.m_sweep.c.y - r1Y; + var length = Math.sqrt(dX * dX + dY * dY); + dX /= length; + dY /= length; + var C = length - this.m_length; + C = b2Math.Clamp(C, -b2Settings.b2_maxLinearCorrection, b2Settings.b2_maxLinearCorrection); + var impulse = -this.m_mass * C; + this.m_u.Set(dX, dY); + var PX = impulse * this.m_u.x; + var PY = impulse * this.m_u.y; + bA.m_sweep.c.x -= bA.m_invMass * PX; + bA.m_sweep.c.y -= bA.m_invMass * PY; + bA.m_sweep.a -= bA.m_invI * (r1X * PY - r1Y * PX); + bB.m_sweep.c.x += bB.m_invMass * PX; + bB.m_sweep.c.y += bB.m_invMass * PY; + bB.m_sweep.a += bB.m_invI * (r2X * PY - r2Y * PX); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return b2Math.Abs(C) < b2Settings.b2_linearSlop +}; +b2DistanceJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1) +}; +b2DistanceJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2) +}; +b2DistanceJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_impulse * this.m_u.x, inv_dt * this.m_impulse * this.m_u.y) +}; +b2DistanceJoint.prototype.GetReactionTorque = function(inv_dt) { + return 0 +}; +b2DistanceJoint.prototype.GetLength = function() { + return this.m_length +}; +b2DistanceJoint.prototype.SetLength = function(length) { + this.m_length = length +}; +b2DistanceJoint.prototype.GetFrequency = function() { + return this.m_frequencyHz +}; +b2DistanceJoint.prototype.SetFrequency = function(hz) { + this.m_frequencyHz = hz +}; +b2DistanceJoint.prototype.GetDampingRatio = function() { + return this.m_dampingRatio +}; +b2DistanceJoint.prototype.SetDampingRatio = function(ratio) { + this.m_dampingRatio = ratio +}; +b2DistanceJoint.prototype.m_localAnchor1 = new b2Vec2; +b2DistanceJoint.prototype.m_localAnchor2 = new b2Vec2; +b2DistanceJoint.prototype.m_u = new b2Vec2; +b2DistanceJoint.prototype.m_frequencyHz = null; +b2DistanceJoint.prototype.m_dampingRatio = null; +b2DistanceJoint.prototype.m_gamma = null; +b2DistanceJoint.prototype.m_bias = null; +b2DistanceJoint.prototype.m_impulse = null; +b2DistanceJoint.prototype.m_mass = null; +b2DistanceJoint.prototype.m_length = null;var b2PulleyJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PulleyJointDef.prototype, b2JointDef.prototype); +b2PulleyJointDef.prototype._super = b2JointDef.prototype; +b2PulleyJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_pulleyJoint; + this.groundAnchorA.Set(-1, 1); + this.groundAnchorB.Set(1, 1); + this.localAnchorA.Set(-1, 0); + this.localAnchorB.Set(1, 0); + this.lengthA = 0; + this.maxLengthA = 0; + this.lengthB = 0; + this.maxLengthB = 0; + this.ratio = 1; + this.collideConnected = true +}; +b2PulleyJointDef.prototype.__varz = function() { + this.groundAnchorA = new b2Vec2; + this.groundAnchorB = new b2Vec2; + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2 +}; +b2PulleyJointDef.prototype.Initialize = function(bA, bB, gaA, gaB, anchorA, anchorB, r) { + this.bodyA = bA; + this.bodyB = bB; + this.groundAnchorA.SetV(gaA); + this.groundAnchorB.SetV(gaB); + this.localAnchorA = this.bodyA.GetLocalPoint(anchorA); + this.localAnchorB = this.bodyB.GetLocalPoint(anchorB); + var d1X = anchorA.x - gaA.x; + var d1Y = anchorA.y - gaA.y; + this.lengthA = Math.sqrt(d1X * d1X + d1Y * d1Y); + var d2X = anchorB.x - gaB.x; + var d2Y = anchorB.y - gaB.y; + this.lengthB = Math.sqrt(d2X * d2X + d2Y * d2Y); + this.ratio = r; + var C = this.lengthA + this.ratio * this.lengthB; + this.maxLengthA = C - this.ratio * b2PulleyJoint.b2_minPulleyLength; + this.maxLengthB = (C - b2PulleyJoint.b2_minPulleyLength) / this.ratio +}; +b2PulleyJointDef.prototype.groundAnchorA = new b2Vec2; +b2PulleyJointDef.prototype.groundAnchorB = new b2Vec2; +b2PulleyJointDef.prototype.localAnchorA = new b2Vec2; +b2PulleyJointDef.prototype.localAnchorB = new b2Vec2; +b2PulleyJointDef.prototype.lengthA = null; +b2PulleyJointDef.prototype.maxLengthA = null; +b2PulleyJointDef.prototype.lengthB = null; +b2PulleyJointDef.prototype.maxLengthB = null; +b2PulleyJointDef.prototype.ratio = null;var b2DistanceJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2DistanceJointDef.prototype, b2JointDef.prototype); +b2DistanceJointDef.prototype._super = b2JointDef.prototype; +b2DistanceJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_distanceJoint; + this.length = 1; + this.frequencyHz = 0; + this.dampingRatio = 0 +}; +b2DistanceJointDef.prototype.__varz = function() { + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2 +}; +b2DistanceJointDef.prototype.Initialize = function(bA, bB, anchorA, anchorB) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchorA)); + this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchorB)); + var dX = anchorB.x - anchorA.x; + var dY = anchorB.y - anchorA.y; + this.length = Math.sqrt(dX * dX + dY * dY); + this.frequencyHz = 0; + this.dampingRatio = 0 +}; +b2DistanceJointDef.prototype.localAnchorA = new b2Vec2; +b2DistanceJointDef.prototype.localAnchorB = new b2Vec2; +b2DistanceJointDef.prototype.length = null; +b2DistanceJointDef.prototype.frequencyHz = null; +b2DistanceJointDef.prototype.dampingRatio = null;var b2FrictionJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2FrictionJointDef.prototype, b2JointDef.prototype); +b2FrictionJointDef.prototype._super = b2JointDef.prototype; +b2FrictionJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_frictionJoint; + this.maxForce = 0; + this.maxTorque = 0 +}; +b2FrictionJointDef.prototype.__varz = function() { + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2 +}; +b2FrictionJointDef.prototype.Initialize = function(bA, bB, anchor) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchor)); + this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchor)) +}; +b2FrictionJointDef.prototype.localAnchorA = new b2Vec2; +b2FrictionJointDef.prototype.localAnchorB = new b2Vec2; +b2FrictionJointDef.prototype.maxForce = null; +b2FrictionJointDef.prototype.maxTorque = null;var b2WeldJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2WeldJointDef.prototype, b2JointDef.prototype); +b2WeldJointDef.prototype._super = b2JointDef.prototype; +b2WeldJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_weldJoint; + this.referenceAngle = 0 +}; +b2WeldJointDef.prototype.__varz = function() { + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2 +}; +b2WeldJointDef.prototype.Initialize = function(bA, bB, anchor) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA.SetV(this.bodyA.GetLocalPoint(anchor)); + this.localAnchorB.SetV(this.bodyB.GetLocalPoint(anchor)); + this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle() +}; +b2WeldJointDef.prototype.localAnchorA = new b2Vec2; +b2WeldJointDef.prototype.localAnchorB = new b2Vec2; +b2WeldJointDef.prototype.referenceAngle = null;var b2GearJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2GearJointDef.prototype, b2JointDef.prototype); +b2GearJointDef.prototype._super = b2JointDef.prototype; +b2GearJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_gearJoint; + this.joint1 = null; + this.joint2 = null; + this.ratio = 1 +}; +b2GearJointDef.prototype.__varz = function() { +}; +b2GearJointDef.prototype.joint1 = null; +b2GearJointDef.prototype.joint2 = null; +b2GearJointDef.prototype.ratio = null;var b2Color = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Color.prototype.__constructor = function(rr, gg, bb) { + this._r = parseInt(255 * b2Math.Clamp(rr, 0, 1)); + this._g = parseInt(255 * b2Math.Clamp(gg, 0, 1)); + this._b = parseInt(255 * b2Math.Clamp(bb, 0, 1)) +}; +b2Color.prototype.__varz = function() { +}; +b2Color.prototype.Set = function(rr, gg, bb) { + this._r = parseInt(255 * b2Math.Clamp(rr, 0, 1)); + this._g = parseInt(255 * b2Math.Clamp(gg, 0, 1)); + this._b = parseInt(255 * b2Math.Clamp(bb, 0, 1)) +}; +b2Color.prototype.__defineGetter__("r", function() { + return this._r +}); +b2Color.prototype.__defineSetter__("r", function(rr) { + this._r = parseInt(255 * b2Math.Clamp(rr, 0, 1)) +}); +b2Color.prototype.__defineGetter__("g", function() { + return this._g +}); +b2Color.prototype.__defineSetter__("g", function(gg) { + this._g = parseInt(255 * b2Math.Clamp(gg, 0, 1)) +}); +b2Color.prototype.__defineGetter__("b", function() { + return this._g +}); +b2Color.prototype.__defineSetter__("b", function(bb) { + this._b = parseInt(255 * b2Math.Clamp(bb, 0, 1)) +}); +b2Color.prototype.__defineGetter__("color", function() { + return this._r << 16 | this._g << 8 | this._b +}); +b2Color.prototype._r = 0; +b2Color.prototype._g = 0; +b2Color.prototype._b = 0;var b2FrictionJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2FrictionJoint.prototype, b2Joint.prototype); +b2FrictionJoint.prototype._super = b2Joint.prototype; +b2FrictionJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + this.m_localAnchorA.SetV(def.localAnchorA); + this.m_localAnchorB.SetV(def.localAnchorB); + this.m_linearMass.SetZero(); + this.m_angularMass = 0; + this.m_linearImpulse.SetZero(); + this.m_angularImpulse = 0; + this.m_maxForce = def.maxForce; + this.m_maxTorque = def.maxTorque +}; +b2FrictionJoint.prototype.__varz = function() { + this.m_localAnchorA = new b2Vec2; + this.m_localAnchorB = new b2Vec2; + this.m_linearImpulse = new b2Vec2; + this.m_linearMass = new b2Mat22 +}; +b2FrictionJoint.prototype.InitVelocityConstraints = function(step) { + var tMat; + var tX; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rAX + tMat.col2.x * rAY; + rAY = tMat.col1.y * rAX + tMat.col2.y * rAY; + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rBX + tMat.col2.x * rBY; + rBY = tMat.col1.y * rBX + tMat.col2.y * rBY; + rBX = tX; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + var K = new b2Mat22; + K.col1.x = mA + mB; + K.col2.x = 0; + K.col1.y = 0; + K.col2.y = mA + mB; + K.col1.x += iA * rAY * rAY; + K.col2.x += -iA * rAX * rAY; + K.col1.y += -iA * rAX * rAY; + K.col2.y += iA * rAX * rAX; + K.col1.x += iB * rBY * rBY; + K.col2.x += -iB * rBX * rBY; + K.col1.y += -iB * rBX * rBY; + K.col2.y += iB * rBX * rBX; + K.GetInverse(this.m_linearMass); + this.m_angularMass = iA + iB; + if(this.m_angularMass > 0) { + this.m_angularMass = 1 / this.m_angularMass + } + if(step.warmStarting) { + this.m_linearImpulse.x *= step.dtRatio; + this.m_linearImpulse.y *= step.dtRatio; + this.m_angularImpulse *= step.dtRatio; + var P = this.m_linearImpulse; + bA.m_linearVelocity.x -= mA * P.x; + bA.m_linearVelocity.y -= mA * P.y; + bA.m_angularVelocity -= iA * (rAX * P.y - rAY * P.x + this.m_angularImpulse); + bB.m_linearVelocity.x += mB * P.x; + bB.m_linearVelocity.y += mB * P.y; + bB.m_angularVelocity += iB * (rBX * P.y - rBY * P.x + this.m_angularImpulse) + }else { + this.m_linearImpulse.SetZero(); + this.m_angularImpulse = 0 + } +}; +b2FrictionJoint.prototype.SolveVelocityConstraints = function(step) { + var tMat; + var tX; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var vA = bA.m_linearVelocity; + var wA = bA.m_angularVelocity; + var vB = bB.m_linearVelocity; + var wB = bB.m_angularVelocity; + var mA = bA.m_invMass; + var mB = bB.m_invMass; + var iA = bA.m_invI; + var iB = bB.m_invI; + tMat = bA.m_xf.R; + var rAX = this.m_localAnchorA.x - bA.m_sweep.localCenter.x; + var rAY = this.m_localAnchorA.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rAX + tMat.col2.x * rAY; + rAY = tMat.col1.y * rAX + tMat.col2.y * rAY; + rAX = tX; + tMat = bB.m_xf.R; + var rBX = this.m_localAnchorB.x - bB.m_sweep.localCenter.x; + var rBY = this.m_localAnchorB.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rBX + tMat.col2.x * rBY; + rBY = tMat.col1.y * rBX + tMat.col2.y * rBY; + rBX = tX; + var maxImpulse; + var Cdot = wB - wA; + var impulse = -this.m_angularMass * Cdot; + var oldImpulse = this.m_angularImpulse; + maxImpulse = step.dt * this.m_maxTorque; + this.m_angularImpulse = b2Math.Clamp(this.m_angularImpulse + impulse, -maxImpulse, maxImpulse); + impulse = this.m_angularImpulse - oldImpulse; + wA -= iA * impulse; + wB += iB * impulse; + var CdotX = vB.x - wB * rBY - vA.x + wA * rAY; + var CdotY = vB.y + wB * rBX - vA.y - wA * rAX; + var impulseV = b2Math.MulMV(this.m_linearMass, new b2Vec2(-CdotX, -CdotY)); + var oldImpulseV = this.m_linearImpulse.Copy(); + this.m_linearImpulse.Add(impulseV); + maxImpulse = step.dt * this.m_maxForce; + if(this.m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) { + this.m_linearImpulse.Normalize(); + this.m_linearImpulse.Multiply(maxImpulse) + } + impulseV = b2Math.SubtractVV(this.m_linearImpulse, oldImpulseV); + vA.x -= mA * impulseV.x; + vA.y -= mA * impulseV.y; + wA -= iA * (rAX * impulseV.y - rAY * impulseV.x); + vB.x += mB * impulseV.x; + vB.y += mB * impulseV.y; + wB += iB * (rBX * impulseV.y - rBY * impulseV.x); + bA.m_angularVelocity = wA; + bB.m_angularVelocity = wB +}; +b2FrictionJoint.prototype.SolvePositionConstraints = function(baumgarte) { + return true +}; +b2FrictionJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchorA) +}; +b2FrictionJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchorB) +}; +b2FrictionJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_linearImpulse.x, inv_dt * this.m_linearImpulse.y) +}; +b2FrictionJoint.prototype.GetReactionTorque = function(inv_dt) { + return inv_dt * this.m_angularImpulse +}; +b2FrictionJoint.prototype.SetMaxForce = function(force) { + this.m_maxForce = force +}; +b2FrictionJoint.prototype.GetMaxForce = function() { + return this.m_maxForce +}; +b2FrictionJoint.prototype.SetMaxTorque = function(torque) { + this.m_maxTorque = torque +}; +b2FrictionJoint.prototype.GetMaxTorque = function() { + return this.m_maxTorque +}; +b2FrictionJoint.prototype.m_localAnchorA = new b2Vec2; +b2FrictionJoint.prototype.m_localAnchorB = new b2Vec2; +b2FrictionJoint.prototype.m_linearImpulse = new b2Vec2; +b2FrictionJoint.prototype.m_angularImpulse = null; +b2FrictionJoint.prototype.m_maxForce = null; +b2FrictionJoint.prototype.m_maxTorque = null; +b2FrictionJoint.prototype.m_linearMass = new b2Mat22; +b2FrictionJoint.prototype.m_angularMass = null;var b2Distance = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Distance.prototype.__constructor = function() { +}; +b2Distance.prototype.__varz = function() { +}; +b2Distance.Distance = function(output, cache, input) { + ++b2Distance.b2_gjkCalls; + var proxyA = input.proxyA; + var proxyB = input.proxyB; + var transformA = input.transformA; + var transformB = input.transformB; + var simplex = b2Distance.s_simplex; + simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); + var vertices = simplex.m_vertices; + var k_maxIters = 20; + var saveA = b2Distance.s_saveA; + var saveB = b2Distance.s_saveB; + var saveCount = 0; + var closestPoint = simplex.GetClosestPoint(); + var distanceSqr1 = closestPoint.LengthSquared(); + var distanceSqr2 = distanceSqr1; + var i = 0; + var p; + var iter = 0; + while(iter < k_maxIters) { + saveCount = simplex.m_count; + for(i = 0;i < saveCount;i++) { + saveA[i] = vertices[i].indexA; + saveB[i] = vertices[i].indexB + } + switch(simplex.m_count) { + case 1: + break; + case 2: + simplex.Solve2(); + break; + case 3: + simplex.Solve3(); + break; + default: + b2Settings.b2Assert(false) + } + if(simplex.m_count == 3) { + break + } + p = simplex.GetClosestPoint(); + distanceSqr2 = p.LengthSquared(); + if(distanceSqr2 > distanceSqr1) { + } + distanceSqr1 = distanceSqr2; + var d = simplex.GetSearchDirection(); + if(d.LengthSquared() < Number.MIN_VALUE * Number.MIN_VALUE) { + break + } + var vertex = vertices[simplex.m_count]; + vertex.indexA = proxyA.GetSupport(b2Math.MulTMV(transformA.R, d.GetNegative())); + vertex.wA = b2Math.MulX(transformA, proxyA.GetVertex(vertex.indexA)); + vertex.indexB = proxyB.GetSupport(b2Math.MulTMV(transformB.R, d)); + vertex.wB = b2Math.MulX(transformB, proxyB.GetVertex(vertex.indexB)); + vertex.w = b2Math.SubtractVV(vertex.wB, vertex.wA); + ++iter; + ++b2Distance.b2_gjkIters; + var duplicate = false; + for(i = 0;i < saveCount;i++) { + if(vertex.indexA == saveA[i] && vertex.indexB == saveB[i]) { + duplicate = true; + break + } + } + if(duplicate) { + break + } + ++simplex.m_count + } + b2Distance.b2_gjkMaxIters = b2Math.Max(b2Distance.b2_gjkMaxIters, iter); + simplex.GetWitnessPoints(output.pointA, output.pointB); + output.distance = b2Math.SubtractVV(output.pointA, output.pointB).Length(); + output.iterations = iter; + simplex.WriteCache(cache); + if(input.useRadii) { + var rA = proxyA.m_radius; + var rB = proxyB.m_radius; + if(output.distance > rA + rB && output.distance > Number.MIN_VALUE) { + output.distance -= rA + rB; + var normal = b2Math.SubtractVV(output.pointB, output.pointA); + normal.Normalize(); + output.pointA.x += rA * normal.x; + output.pointA.y += rA * normal.y; + output.pointB.x -= rB * normal.x; + output.pointB.y -= rB * normal.y + }else { + p = new b2Vec2; + p.x = 0.5 * (output.pointA.x + output.pointB.x); + p.y = 0.5 * (output.pointA.y + output.pointB.y); + output.pointA.x = output.pointB.x = p.x; + output.pointA.y = output.pointB.y = p.y; + output.distance = 0 + } + } +}; +b2Distance.b2_gjkCalls = 0; +b2Distance.b2_gjkIters = 0; +b2Distance.b2_gjkMaxIters = 0; +b2Distance.s_simplex = new b2Simplex; +b2Distance.s_saveA = new Array(3); +b2Distance.s_saveB = new Array(3);var b2MouseJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2MouseJoint.prototype, b2Joint.prototype); +b2MouseJoint.prototype._super = b2Joint.prototype; +b2MouseJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + this.m_target.SetV(def.target); + var tX = this.m_target.x - this.m_bodyB.m_xf.position.x; + var tY = this.m_target.y - this.m_bodyB.m_xf.position.y; + var tMat = this.m_bodyB.m_xf.R; + this.m_localAnchor.x = tX * tMat.col1.x + tY * tMat.col1.y; + this.m_localAnchor.y = tX * tMat.col2.x + tY * tMat.col2.y; + this.m_maxForce = def.maxForce; + this.m_impulse.SetZero(); + this.m_frequencyHz = def.frequencyHz; + this.m_dampingRatio = def.dampingRatio; + this.m_beta = 0; + this.m_gamma = 0 +}; +b2MouseJoint.prototype.__varz = function() { + this.K = new b2Mat22; + this.K1 = new b2Mat22; + this.K2 = new b2Mat22; + this.m_localAnchor = new b2Vec2; + this.m_target = new b2Vec2; + this.m_impulse = new b2Vec2; + this.m_mass = new b2Mat22; + this.m_C = new b2Vec2 +}; +b2MouseJoint.prototype.InitVelocityConstraints = function(step) { + var b = this.m_bodyB; + var mass = b.GetMass(); + var omega = 2 * Math.PI * this.m_frequencyHz; + var d = 2 * mass * this.m_dampingRatio * omega; + var k = mass * omega * omega; + this.m_gamma = step.dt * (d + step.dt * k); + this.m_gamma = this.m_gamma != 0 ? 1 / this.m_gamma : 0; + this.m_beta = step.dt * k * this.m_gamma; + var tMat; + tMat = b.m_xf.R; + var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; + var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; + var tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + var invMass = b.m_invMass; + var invI = b.m_invI; + this.K1.col1.x = invMass; + this.K1.col2.x = 0; + this.K1.col1.y = 0; + this.K1.col2.y = invMass; + this.K2.col1.x = invI * rY * rY; + this.K2.col2.x = -invI * rX * rY; + this.K2.col1.y = -invI * rX * rY; + this.K2.col2.y = invI * rX * rX; + this.K.SetM(this.K1); + this.K.AddM(this.K2); + this.K.col1.x += this.m_gamma; + this.K.col2.y += this.m_gamma; + this.K.GetInverse(this.m_mass); + this.m_C.x = b.m_sweep.c.x + rX - this.m_target.x; + this.m_C.y = b.m_sweep.c.y + rY - this.m_target.y; + b.m_angularVelocity *= 0.98; + this.m_impulse.x *= step.dtRatio; + this.m_impulse.y *= step.dtRatio; + b.m_linearVelocity.x += invMass * this.m_impulse.x; + b.m_linearVelocity.y += invMass * this.m_impulse.y; + b.m_angularVelocity += invI * (rX * this.m_impulse.y - rY * this.m_impulse.x) +}; +b2MouseJoint.prototype.SolveVelocityConstraints = function(step) { + var b = this.m_bodyB; + var tMat; + var tX; + var tY; + tMat = b.m_xf.R; + var rX = this.m_localAnchor.x - b.m_sweep.localCenter.x; + var rY = this.m_localAnchor.y - b.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + var CdotX = b.m_linearVelocity.x + -b.m_angularVelocity * rY; + var CdotY = b.m_linearVelocity.y + b.m_angularVelocity * rX; + tMat = this.m_mass; + tX = CdotX + this.m_beta * this.m_C.x + this.m_gamma * this.m_impulse.x; + tY = CdotY + this.m_beta * this.m_C.y + this.m_gamma * this.m_impulse.y; + var impulseX = -(tMat.col1.x * tX + tMat.col2.x * tY); + var impulseY = -(tMat.col1.y * tX + tMat.col2.y * tY); + var oldImpulseX = this.m_impulse.x; + var oldImpulseY = this.m_impulse.y; + this.m_impulse.x += impulseX; + this.m_impulse.y += impulseY; + var maxImpulse = step.dt * this.m_maxForce; + if(this.m_impulse.LengthSquared() > maxImpulse * maxImpulse) { + this.m_impulse.Multiply(maxImpulse / this.m_impulse.Length()) + } + impulseX = this.m_impulse.x - oldImpulseX; + impulseY = this.m_impulse.y - oldImpulseY; + b.m_linearVelocity.x += b.m_invMass * impulseX; + b.m_linearVelocity.y += b.m_invMass * impulseY; + b.m_angularVelocity += b.m_invI * (rX * impulseY - rY * impulseX) +}; +b2MouseJoint.prototype.SolvePositionConstraints = function(baumgarte) { + return true +}; +b2MouseJoint.prototype.GetAnchorA = function() { + return this.m_target +}; +b2MouseJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor) +}; +b2MouseJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_impulse.x, inv_dt * this.m_impulse.y) +}; +b2MouseJoint.prototype.GetReactionTorque = function(inv_dt) { + return 0 +}; +b2MouseJoint.prototype.GetTarget = function() { + return this.m_target +}; +b2MouseJoint.prototype.SetTarget = function(target) { + if(this.m_bodyB.IsAwake() == false) { + this.m_bodyB.SetAwake(true) + } + this.m_target = target +}; +b2MouseJoint.prototype.GetMaxForce = function() { + return this.m_maxForce +}; +b2MouseJoint.prototype.SetMaxForce = function(maxForce) { + this.m_maxForce = maxForce +}; +b2MouseJoint.prototype.GetFrequency = function() { + return this.m_frequencyHz +}; +b2MouseJoint.prototype.SetFrequency = function(hz) { + this.m_frequencyHz = hz +}; +b2MouseJoint.prototype.GetDampingRatio = function() { + return this.m_dampingRatio +}; +b2MouseJoint.prototype.SetDampingRatio = function(ratio) { + this.m_dampingRatio = ratio +}; +b2MouseJoint.prototype.K = new b2Mat22; +b2MouseJoint.prototype.K1 = new b2Mat22; +b2MouseJoint.prototype.K2 = new b2Mat22; +b2MouseJoint.prototype.m_localAnchor = new b2Vec2; +b2MouseJoint.prototype.m_target = new b2Vec2; +b2MouseJoint.prototype.m_impulse = new b2Vec2; +b2MouseJoint.prototype.m_mass = new b2Mat22; +b2MouseJoint.prototype.m_C = new b2Vec2; +b2MouseJoint.prototype.m_maxForce = null; +b2MouseJoint.prototype.m_frequencyHz = null; +b2MouseJoint.prototype.m_dampingRatio = null; +b2MouseJoint.prototype.m_beta = null; +b2MouseJoint.prototype.m_gamma = null;var b2PrismaticJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PrismaticJointDef.prototype, b2JointDef.prototype); +b2PrismaticJointDef.prototype._super = b2JointDef.prototype; +b2PrismaticJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_prismaticJoint; + this.localAxisA.Set(1, 0); + this.referenceAngle = 0; + this.enableLimit = false; + this.lowerTranslation = 0; + this.upperTranslation = 0; + this.enableMotor = false; + this.maxMotorForce = 0; + this.motorSpeed = 0 +}; +b2PrismaticJointDef.prototype.__varz = function() { + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2; + this.localAxisA = new b2Vec2 +}; +b2PrismaticJointDef.prototype.Initialize = function(bA, bB, anchor, axis) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA = this.bodyA.GetLocalPoint(anchor); + this.localAnchorB = this.bodyB.GetLocalPoint(anchor); + this.localAxisA = this.bodyA.GetLocalVector(axis); + this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle() +}; +b2PrismaticJointDef.prototype.localAnchorA = new b2Vec2; +b2PrismaticJointDef.prototype.localAnchorB = new b2Vec2; +b2PrismaticJointDef.prototype.localAxisA = new b2Vec2; +b2PrismaticJointDef.prototype.referenceAngle = null; +b2PrismaticJointDef.prototype.enableLimit = null; +b2PrismaticJointDef.prototype.lowerTranslation = null; +b2PrismaticJointDef.prototype.upperTranslation = null; +b2PrismaticJointDef.prototype.enableMotor = null; +b2PrismaticJointDef.prototype.maxMotorForce = null; +b2PrismaticJointDef.prototype.motorSpeed = null;var b2TimeOfImpact = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2TimeOfImpact.prototype.__constructor = function() { +}; +b2TimeOfImpact.prototype.__varz = function() { +}; +b2TimeOfImpact.TimeOfImpact = function(input) { + ++b2TimeOfImpact.b2_toiCalls; + var proxyA = input.proxyA; + var proxyB = input.proxyB; + var sweepA = input.sweepA; + var sweepB = input.sweepB; + b2Settings.b2Assert(sweepA.t0 == sweepB.t0); + b2Settings.b2Assert(1 - sweepA.t0 > Number.MIN_VALUE); + var radius = proxyA.m_radius + proxyB.m_radius; + var tolerance = input.tolerance; + var alpha = 0; + var k_maxIterations = 1E3; + var iter = 0; + var target = 0; + b2TimeOfImpact.s_cache.count = 0; + b2TimeOfImpact.s_distanceInput.useRadii = false; + for(;;) { + sweepA.GetTransform(b2TimeOfImpact.s_xfA, alpha); + sweepB.GetTransform(b2TimeOfImpact.s_xfB, alpha); + b2TimeOfImpact.s_distanceInput.proxyA = proxyA; + b2TimeOfImpact.s_distanceInput.proxyB = proxyB; + b2TimeOfImpact.s_distanceInput.transformA = b2TimeOfImpact.s_xfA; + b2TimeOfImpact.s_distanceInput.transformB = b2TimeOfImpact.s_xfB; + b2Distance.Distance(b2TimeOfImpact.s_distanceOutput, b2TimeOfImpact.s_cache, b2TimeOfImpact.s_distanceInput); + if(b2TimeOfImpact.s_distanceOutput.distance <= 0) { + alpha = 1; + break + } + b2TimeOfImpact.s_fcn.Initialize(b2TimeOfImpact.s_cache, proxyA, b2TimeOfImpact.s_xfA, proxyB, b2TimeOfImpact.s_xfB); + var separation = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); + if(separation <= 0) { + alpha = 1; + break + } + if(iter == 0) { + if(separation > radius) { + target = b2Math.Max(radius - tolerance, 0.75 * radius) + }else { + target = b2Math.Max(separation - tolerance, 0.02 * radius) + } + } + if(separation - target < 0.5 * tolerance) { + if(iter == 0) { + alpha = 1; + break + } + break + } + var newAlpha = alpha; + var x1 = alpha; + var x2 = 1; + var f1 = separation; + sweepA.GetTransform(b2TimeOfImpact.s_xfA, x2); + sweepB.GetTransform(b2TimeOfImpact.s_xfB, x2); + var f2 = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); + if(f2 >= target) { + alpha = 1; + break + } + var rootIterCount = 0; + for(;;) { + var x; + if(rootIterCount & 1) { + x = x1 + (target - f1) * (x2 - x1) / (f2 - f1) + }else { + x = 0.5 * (x1 + x2) + } + sweepA.GetTransform(b2TimeOfImpact.s_xfA, x); + sweepB.GetTransform(b2TimeOfImpact.s_xfB, x); + var f = b2TimeOfImpact.s_fcn.Evaluate(b2TimeOfImpact.s_xfA, b2TimeOfImpact.s_xfB); + if(b2Math.Abs(f - target) < 0.025 * tolerance) { + newAlpha = x; + break + } + if(f > target) { + x1 = x; + f1 = f + }else { + x2 = x; + f2 = f + } + ++rootIterCount; + ++b2TimeOfImpact.b2_toiRootIters; + if(rootIterCount == 50) { + break + } + } + b2TimeOfImpact.b2_toiMaxRootIters = b2Math.Max(b2TimeOfImpact.b2_toiMaxRootIters, rootIterCount); + if(newAlpha < (1 + 100 * Number.MIN_VALUE) * alpha) { + break + } + alpha = newAlpha; + iter++; + ++b2TimeOfImpact.b2_toiIters; + if(iter == k_maxIterations) { + break + } + } + b2TimeOfImpact.b2_toiMaxIters = b2Math.Max(b2TimeOfImpact.b2_toiMaxIters, iter); + return alpha +}; +b2TimeOfImpact.b2_toiCalls = 0; +b2TimeOfImpact.b2_toiIters = 0; +b2TimeOfImpact.b2_toiMaxIters = 0; +b2TimeOfImpact.b2_toiRootIters = 0; +b2TimeOfImpact.b2_toiMaxRootIters = 0; +b2TimeOfImpact.s_cache = new b2SimplexCache; +b2TimeOfImpact.s_distanceInput = new b2DistanceInput; +b2TimeOfImpact.s_xfA = new b2Transform; +b2TimeOfImpact.s_xfB = new b2Transform; +b2TimeOfImpact.s_fcn = new b2SeparationFunction; +b2TimeOfImpact.s_distanceOutput = new b2DistanceOutput;var b2GearJoint = function() { + b2Joint.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2GearJoint.prototype, b2Joint.prototype); +b2GearJoint.prototype._super = b2Joint.prototype; +b2GearJoint.prototype.__constructor = function(def) { + this._super.__constructor.apply(this, [def]); + var type1 = def.joint1.m_type; + var type2 = def.joint2.m_type; + this.m_revolute1 = null; + this.m_prismatic1 = null; + this.m_revolute2 = null; + this.m_prismatic2 = null; + var coordinate1; + var coordinate2; + this.m_ground1 = def.joint1.GetBodyA(); + this.m_bodyA = def.joint1.GetBodyB(); + if(type1 == b2Joint.e_revoluteJoint) { + this.m_revolute1 = def.joint1; + this.m_groundAnchor1.SetV(this.m_revolute1.m_localAnchor1); + this.m_localAnchor1.SetV(this.m_revolute1.m_localAnchor2); + coordinate1 = this.m_revolute1.GetJointAngle() + }else { + this.m_prismatic1 = def.joint1; + this.m_groundAnchor1.SetV(this.m_prismatic1.m_localAnchor1); + this.m_localAnchor1.SetV(this.m_prismatic1.m_localAnchor2); + coordinate1 = this.m_prismatic1.GetJointTranslation() + } + this.m_ground2 = def.joint2.GetBodyA(); + this.m_bodyB = def.joint2.GetBodyB(); + if(type2 == b2Joint.e_revoluteJoint) { + this.m_revolute2 = def.joint2; + this.m_groundAnchor2.SetV(this.m_revolute2.m_localAnchor1); + this.m_localAnchor2.SetV(this.m_revolute2.m_localAnchor2); + coordinate2 = this.m_revolute2.GetJointAngle() + }else { + this.m_prismatic2 = def.joint2; + this.m_groundAnchor2.SetV(this.m_prismatic2.m_localAnchor1); + this.m_localAnchor2.SetV(this.m_prismatic2.m_localAnchor2); + coordinate2 = this.m_prismatic2.GetJointTranslation() + } + this.m_ratio = def.ratio; + this.m_constant = coordinate1 + this.m_ratio * coordinate2; + this.m_impulse = 0 +}; +b2GearJoint.prototype.__varz = function() { + this.m_groundAnchor1 = new b2Vec2; + this.m_groundAnchor2 = new b2Vec2; + this.m_localAnchor1 = new b2Vec2; + this.m_localAnchor2 = new b2Vec2; + this.m_J = new b2Jacobian +}; +b2GearJoint.prototype.InitVelocityConstraints = function(step) { + var g1 = this.m_ground1; + var g2 = this.m_ground2; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var ugX; + var ugY; + var rX; + var rY; + var tMat; + var tVec; + var crug; + var tX; + var K = 0; + this.m_J.SetZero(); + if(this.m_revolute1) { + this.m_J.angularA = -1; + K += bA.m_invI + }else { + tMat = g1.m_xf.R; + tVec = this.m_prismatic1.m_localXAxis1; + ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = bA.m_xf.R; + rX = this.m_localAnchor1.x - bA.m_sweep.localCenter.x; + rY = this.m_localAnchor1.y - bA.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + crug = rX * ugY - rY * ugX; + this.m_J.linearA.Set(-ugX, -ugY); + this.m_J.angularA = -crug; + K += bA.m_invMass + bA.m_invI * crug * crug + } + if(this.m_revolute2) { + this.m_J.angularB = -this.m_ratio; + K += this.m_ratio * this.m_ratio * bB.m_invI + }else { + tMat = g2.m_xf.R; + tVec = this.m_prismatic2.m_localXAxis1; + ugX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + ugY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = bB.m_xf.R; + rX = this.m_localAnchor2.x - bB.m_sweep.localCenter.x; + rY = this.m_localAnchor2.y - bB.m_sweep.localCenter.y; + tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + crug = rX * ugY - rY * ugX; + this.m_J.linearB.Set(-this.m_ratio * ugX, -this.m_ratio * ugY); + this.m_J.angularB = -this.m_ratio * crug; + K += this.m_ratio * this.m_ratio * (bB.m_invMass + bB.m_invI * crug * crug) + } + this.m_mass = K > 0 ? 1 / K : 0; + if(step.warmStarting) { + bA.m_linearVelocity.x += bA.m_invMass * this.m_impulse * this.m_J.linearA.x; + bA.m_linearVelocity.y += bA.m_invMass * this.m_impulse * this.m_J.linearA.y; + bA.m_angularVelocity += bA.m_invI * this.m_impulse * this.m_J.angularA; + bB.m_linearVelocity.x += bB.m_invMass * this.m_impulse * this.m_J.linearB.x; + bB.m_linearVelocity.y += bB.m_invMass * this.m_impulse * this.m_J.linearB.y; + bB.m_angularVelocity += bB.m_invI * this.m_impulse * this.m_J.angularB + }else { + this.m_impulse = 0 + } +}; +b2GearJoint.prototype.SolveVelocityConstraints = function(step) { + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var Cdot = this.m_J.Compute(bA.m_linearVelocity, bA.m_angularVelocity, bB.m_linearVelocity, bB.m_angularVelocity); + var impulse = -this.m_mass * Cdot; + this.m_impulse += impulse; + bA.m_linearVelocity.x += bA.m_invMass * impulse * this.m_J.linearA.x; + bA.m_linearVelocity.y += bA.m_invMass * impulse * this.m_J.linearA.y; + bA.m_angularVelocity += bA.m_invI * impulse * this.m_J.angularA; + bB.m_linearVelocity.x += bB.m_invMass * impulse * this.m_J.linearB.x; + bB.m_linearVelocity.y += bB.m_invMass * impulse * this.m_J.linearB.y; + bB.m_angularVelocity += bB.m_invI * impulse * this.m_J.angularB +}; +b2GearJoint.prototype.SolvePositionConstraints = function(baumgarte) { + var linearError = 0; + var bA = this.m_bodyA; + var bB = this.m_bodyB; + var coordinate1; + var coordinate2; + if(this.m_revolute1) { + coordinate1 = this.m_revolute1.GetJointAngle() + }else { + coordinate1 = this.m_prismatic1.GetJointTranslation() + } + if(this.m_revolute2) { + coordinate2 = this.m_revolute2.GetJointAngle() + }else { + coordinate2 = this.m_prismatic2.GetJointTranslation() + } + var C = this.m_constant - (coordinate1 + this.m_ratio * coordinate2); + var impulse = -this.m_mass * C; + bA.m_sweep.c.x += bA.m_invMass * impulse * this.m_J.linearA.x; + bA.m_sweep.c.y += bA.m_invMass * impulse * this.m_J.linearA.y; + bA.m_sweep.a += bA.m_invI * impulse * this.m_J.angularA; + bB.m_sweep.c.x += bB.m_invMass * impulse * this.m_J.linearB.x; + bB.m_sweep.c.y += bB.m_invMass * impulse * this.m_J.linearB.y; + bB.m_sweep.a += bB.m_invI * impulse * this.m_J.angularB; + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + return linearError < b2Settings.b2_linearSlop +}; +b2GearJoint.prototype.GetAnchorA = function() { + return this.m_bodyA.GetWorldPoint(this.m_localAnchor1) +}; +b2GearJoint.prototype.GetAnchorB = function() { + return this.m_bodyB.GetWorldPoint(this.m_localAnchor2) +}; +b2GearJoint.prototype.GetReactionForce = function(inv_dt) { + return new b2Vec2(inv_dt * this.m_impulse * this.m_J.linearB.x, inv_dt * this.m_impulse * this.m_J.linearB.y) +}; +b2GearJoint.prototype.GetReactionTorque = function(inv_dt) { + var tMat = this.m_bodyB.m_xf.R; + var rX = this.m_localAnchor1.x - this.m_bodyB.m_sweep.localCenter.x; + var rY = this.m_localAnchor1.y - this.m_bodyB.m_sweep.localCenter.y; + var tX = tMat.col1.x * rX + tMat.col2.x * rY; + rY = tMat.col1.y * rX + tMat.col2.y * rY; + rX = tX; + var PX = this.m_impulse * this.m_J.linearB.x; + var PY = this.m_impulse * this.m_J.linearB.y; + return inv_dt * (this.m_impulse * this.m_J.angularB - rX * PY + rY * PX) +}; +b2GearJoint.prototype.GetRatio = function() { + return this.m_ratio +}; +b2GearJoint.prototype.SetRatio = function(ratio) { + this.m_ratio = ratio +}; +b2GearJoint.prototype.m_ground1 = null; +b2GearJoint.prototype.m_ground2 = null; +b2GearJoint.prototype.m_revolute1 = null; +b2GearJoint.prototype.m_prismatic1 = null; +b2GearJoint.prototype.m_revolute2 = null; +b2GearJoint.prototype.m_prismatic2 = null; +b2GearJoint.prototype.m_groundAnchor1 = new b2Vec2; +b2GearJoint.prototype.m_groundAnchor2 = new b2Vec2; +b2GearJoint.prototype.m_localAnchor1 = new b2Vec2; +b2GearJoint.prototype.m_localAnchor2 = new b2Vec2; +b2GearJoint.prototype.m_J = new b2Jacobian; +b2GearJoint.prototype.m_constant = null; +b2GearJoint.prototype.m_ratio = null; +b2GearJoint.prototype.m_mass = null; +b2GearJoint.prototype.m_impulse = null;var b2TOIInput = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2TOIInput.prototype.__constructor = function() { +}; +b2TOIInput.prototype.__varz = function() { + this.proxyA = new b2DistanceProxy; + this.proxyB = new b2DistanceProxy; + this.sweepA = new b2Sweep; + this.sweepB = new b2Sweep +}; +b2TOIInput.prototype.proxyA = new b2DistanceProxy; +b2TOIInput.prototype.proxyB = new b2DistanceProxy; +b2TOIInput.prototype.sweepA = new b2Sweep; +b2TOIInput.prototype.sweepB = new b2Sweep; +b2TOIInput.prototype.tolerance = null;var b2RevoluteJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2RevoluteJointDef.prototype, b2JointDef.prototype); +b2RevoluteJointDef.prototype._super = b2JointDef.prototype; +b2RevoluteJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_revoluteJoint; + this.localAnchorA.Set(0, 0); + this.localAnchorB.Set(0, 0); + this.referenceAngle = 0; + this.lowerAngle = 0; + this.upperAngle = 0; + this.maxMotorTorque = 0; + this.motorSpeed = 0; + this.enableLimit = false; + this.enableMotor = false +}; +b2RevoluteJointDef.prototype.__varz = function() { + this.localAnchorA = new b2Vec2; + this.localAnchorB = new b2Vec2 +}; +b2RevoluteJointDef.prototype.Initialize = function(bA, bB, anchor) { + this.bodyA = bA; + this.bodyB = bB; + this.localAnchorA = this.bodyA.GetLocalPoint(anchor); + this.localAnchorB = this.bodyB.GetLocalPoint(anchor); + this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle() +}; +b2RevoluteJointDef.prototype.localAnchorA = new b2Vec2; +b2RevoluteJointDef.prototype.localAnchorB = new b2Vec2; +b2RevoluteJointDef.prototype.referenceAngle = null; +b2RevoluteJointDef.prototype.enableLimit = null; +b2RevoluteJointDef.prototype.lowerAngle = null; +b2RevoluteJointDef.prototype.upperAngle = null; +b2RevoluteJointDef.prototype.enableMotor = null; +b2RevoluteJointDef.prototype.motorSpeed = null; +b2RevoluteJointDef.prototype.maxMotorTorque = null;var b2MouseJointDef = function() { + b2JointDef.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2MouseJointDef.prototype, b2JointDef.prototype); +b2MouseJointDef.prototype._super = b2JointDef.prototype; +b2MouseJointDef.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments); + this.type = b2Joint.e_mouseJoint; + this.maxForce = 0; + this.frequencyHz = 5; + this.dampingRatio = 0.7 +}; +b2MouseJointDef.prototype.__varz = function() { + this.target = new b2Vec2 +}; +b2MouseJointDef.prototype.target = new b2Vec2; +b2MouseJointDef.prototype.maxForce = null; +b2MouseJointDef.prototype.frequencyHz = null; +b2MouseJointDef.prototype.dampingRatio = null;var b2Contact = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Contact.prototype.__constructor = function() { +}; +b2Contact.prototype.__varz = function() { + this.m_nodeA = new b2ContactEdge; + this.m_nodeB = new b2ContactEdge; + this.m_manifold = new b2Manifold; + this.m_oldManifold = new b2Manifold +}; +b2Contact.s_input = new b2TOIInput; +b2Contact.e_sensorFlag = 1; +b2Contact.e_continuousFlag = 2; +b2Contact.e_islandFlag = 4; +b2Contact.e_toiFlag = 8; +b2Contact.e_touchingFlag = 16; +b2Contact.e_enabledFlag = 32; +b2Contact.e_filterFlag = 64; +b2Contact.prototype.Reset = function(fixtureA, fixtureB) { + this.m_flags = b2Contact.e_enabledFlag; + if(!fixtureA || !fixtureB) { + this.m_fixtureA = null; + this.m_fixtureB = null; + return + } + if(fixtureA.IsSensor() || fixtureB.IsSensor()) { + this.m_flags |= b2Contact.e_sensorFlag + } + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if(bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet()) { + this.m_flags |= b2Contact.e_continuousFlag + } + this.m_fixtureA = fixtureA; + this.m_fixtureB = fixtureB; + this.m_manifold.m_pointCount = 0; + this.m_prev = null; + this.m_next = null; + this.m_nodeA.contact = null; + this.m_nodeA.prev = null; + this.m_nodeA.next = null; + this.m_nodeA.other = null; + this.m_nodeB.contact = null; + this.m_nodeB.prev = null; + this.m_nodeB.next = null; + this.m_nodeB.other = null +}; +b2Contact.prototype.Update = function(listener) { + var tManifold = this.m_oldManifold; + this.m_oldManifold = this.m_manifold; + this.m_manifold = tManifold; + this.m_flags |= b2Contact.e_enabledFlag; + var touching = false; + var wasTouching = (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag; + var bodyA = this.m_fixtureA.m_body; + var bodyB = this.m_fixtureB.m_body; + var aabbOverlap = this.m_fixtureA.m_aabb.TestOverlap(this.m_fixtureB.m_aabb); + if(this.m_flags & b2Contact.e_sensorFlag) { + if(aabbOverlap) { + var shapeA = this.m_fixtureA.GetShape(); + var shapeB = this.m_fixtureB.GetShape(); + var xfA = bodyA.GetTransform(); + var xfB = bodyB.GetTransform(); + touching = b2Shape.TestOverlap(shapeA, xfA, shapeB, xfB) + } + this.m_manifold.m_pointCount = 0 + }else { + if(bodyA.GetType() != b2Body.b2_dynamicBody || bodyA.IsBullet() || bodyB.GetType() != b2Body.b2_dynamicBody || bodyB.IsBullet()) { + this.m_flags |= b2Contact.e_continuousFlag + }else { + this.m_flags &= ~b2Contact.e_continuousFlag + } + if(aabbOverlap) { + this.Evaluate(); + touching = this.m_manifold.m_pointCount > 0; + for(var i = 0;i < this.m_manifold.m_pointCount;++i) { + var mp2 = this.m_manifold.m_points[i]; + mp2.m_normalImpulse = 0; + mp2.m_tangentImpulse = 0; + var id2 = mp2.m_id; + for(var j = 0;j < this.m_oldManifold.m_pointCount;++j) { + var mp1 = this.m_oldManifold.m_points[j]; + if(mp1.m_id.key == id2.key) { + mp2.m_normalImpulse = mp1.m_normalImpulse; + mp2.m_tangentImpulse = mp1.m_tangentImpulse; + break + } + } + } + }else { + this.m_manifold.m_pointCount = 0 + } + if(touching != wasTouching) { + bodyA.SetAwake(true); + bodyB.SetAwake(true) + } + } + if(touching) { + this.m_flags |= b2Contact.e_touchingFlag + }else { + this.m_flags &= ~b2Contact.e_touchingFlag + } + if(wasTouching == false && touching == true) { + listener.BeginContact(this) + } + if(wasTouching == true && touching == false) { + listener.EndContact(this) + } + if((this.m_flags & b2Contact.e_sensorFlag) == 0) { + listener.PreSolve(this, this.m_oldManifold) + } +}; +b2Contact.prototype.Evaluate = function() { +}; +b2Contact.prototype.ComputeTOI = function(sweepA, sweepB) { + b2Contact.s_input.proxyA.Set(this.m_fixtureA.GetShape()); + b2Contact.s_input.proxyB.Set(this.m_fixtureB.GetShape()); + b2Contact.s_input.sweepA = sweepA; + b2Contact.s_input.sweepB = sweepB; + b2Contact.s_input.tolerance = b2Settings.b2_linearSlop; + return b2TimeOfImpact.TimeOfImpact(b2Contact.s_input) +}; +b2Contact.prototype.GetManifold = function() { + return this.m_manifold +}; +b2Contact.prototype.GetWorldManifold = function(worldManifold) { + var bodyA = this.m_fixtureA.GetBody(); + var bodyB = this.m_fixtureB.GetBody(); + var shapeA = this.m_fixtureA.GetShape(); + var shapeB = this.m_fixtureB.GetShape(); + worldManifold.Initialize(this.m_manifold, bodyA.GetTransform(), shapeA.m_radius, bodyB.GetTransform(), shapeB.m_radius) +}; +b2Contact.prototype.IsTouching = function() { + return(this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag +}; +b2Contact.prototype.IsContinuous = function() { + return(this.m_flags & b2Contact.e_continuousFlag) == b2Contact.e_continuousFlag +}; +b2Contact.prototype.SetSensor = function(sensor) { + if(sensor) { + this.m_flags |= b2Contact.e_sensorFlag + }else { + this.m_flags &= ~b2Contact.e_sensorFlag + } +}; +b2Contact.prototype.IsSensor = function() { + return(this.m_flags & b2Contact.e_sensorFlag) == b2Contact.e_sensorFlag +}; +b2Contact.prototype.SetEnabled = function(flag) { + if(flag) { + this.m_flags |= b2Contact.e_enabledFlag + }else { + this.m_flags &= ~b2Contact.e_enabledFlag + } +}; +b2Contact.prototype.IsEnabled = function() { + return(this.m_flags & b2Contact.e_enabledFlag) == b2Contact.e_enabledFlag +}; +b2Contact.prototype.GetNext = function() { + return this.m_next +}; +b2Contact.prototype.GetFixtureA = function() { + return this.m_fixtureA +}; +b2Contact.prototype.GetFixtureB = function() { + return this.m_fixtureB +}; +b2Contact.prototype.FlagForFiltering = function() { + this.m_flags |= b2Contact.e_filterFlag +}; +b2Contact.prototype.m_flags = 0; +b2Contact.prototype.m_prev = null; +b2Contact.prototype.m_next = null; +b2Contact.prototype.m_nodeA = new b2ContactEdge; +b2Contact.prototype.m_nodeB = new b2ContactEdge; +b2Contact.prototype.m_fixtureA = null; +b2Contact.prototype.m_fixtureB = null; +b2Contact.prototype.m_manifold = new b2Manifold; +b2Contact.prototype.m_oldManifold = new b2Manifold; +b2Contact.prototype.m_toi = null;var b2ContactConstraint = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactConstraint.prototype.__constructor = function() { + this.points = new Array(b2Settings.b2_maxManifoldPoints); + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;i++) { + this.points[i] = new b2ContactConstraintPoint + } +}; +b2ContactConstraint.prototype.__varz = function() { + this.localPlaneNormal = new b2Vec2; + this.localPoint = new b2Vec2; + this.normal = new b2Vec2; + this.normalMass = new b2Mat22; + this.K = new b2Mat22 +}; +b2ContactConstraint.prototype.points = null; +b2ContactConstraint.prototype.localPlaneNormal = new b2Vec2; +b2ContactConstraint.prototype.localPoint = new b2Vec2; +b2ContactConstraint.prototype.normal = new b2Vec2; +b2ContactConstraint.prototype.normalMass = new b2Mat22; +b2ContactConstraint.prototype.K = new b2Mat22; +b2ContactConstraint.prototype.bodyA = null; +b2ContactConstraint.prototype.bodyB = null; +b2ContactConstraint.prototype.type = 0; +b2ContactConstraint.prototype.radius = null; +b2ContactConstraint.prototype.friction = null; +b2ContactConstraint.prototype.restitution = null; +b2ContactConstraint.prototype.pointCount = 0; +b2ContactConstraint.prototype.manifold = null;var b2ContactResult = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactResult.prototype.__constructor = function() { +}; +b2ContactResult.prototype.__varz = function() { + this.position = new b2Vec2; + this.normal = new b2Vec2; + this.id = new b2ContactID +}; +b2ContactResult.prototype.shape1 = null; +b2ContactResult.prototype.shape2 = null; +b2ContactResult.prototype.position = new b2Vec2; +b2ContactResult.prototype.normal = new b2Vec2; +b2ContactResult.prototype.normalImpulse = null; +b2ContactResult.prototype.tangentImpulse = null; +b2ContactResult.prototype.id = new b2ContactID;var b2PolygonContact = function() { + b2Contact.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PolygonContact.prototype, b2Contact.prototype); +b2PolygonContact.prototype._super = b2Contact.prototype; +b2PolygonContact.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2PolygonContact.prototype.__varz = function() { +}; +b2PolygonContact.Create = function(allocator) { + return new b2PolygonContact +}; +b2PolygonContact.Destroy = function(contact, allocator) { +}; +b2PolygonContact.prototype.Evaluate = function() { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + b2Collision.CollidePolygons(this.m_manifold, this.m_fixtureA.GetShape(), bA.m_xf, this.m_fixtureB.GetShape(), bB.m_xf) +}; +b2PolygonContact.prototype.Reset = function(fixtureA, fixtureB) { + this._super.Reset.apply(this, [fixtureA, fixtureB]) +};var ClipVertex = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +ClipVertex.prototype.__constructor = function() { +}; +ClipVertex.prototype.__varz = function() { + this.v = new b2Vec2; + this.id = new b2ContactID +}; +ClipVertex.prototype.Set = function(other) { + this.v.SetV(other.v); + this.id.Set(other.id) +}; +ClipVertex.prototype.v = new b2Vec2; +ClipVertex.prototype.id = new b2ContactID;var b2ContactFilter = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactFilter.prototype.__constructor = function() { +}; +b2ContactFilter.prototype.__varz = function() { +}; +b2ContactFilter.b2_defaultFilter = new b2ContactFilter; +b2ContactFilter.prototype.ShouldCollide = function(fixtureA, fixtureB) { + var filter1 = fixtureA.GetFilterData(); + var filter2 = fixtureB.GetFilterData(); + if(filter1.groupIndex == filter2.groupIndex && filter1.groupIndex != 0) { + return filter1.groupIndex > 0 + } + var collide = (filter1.maskBits & filter2.categoryBits) != 0 && (filter1.categoryBits & filter2.maskBits) != 0; + return collide +}; +b2ContactFilter.prototype.RayCollide = function(userData, fixture) { + if(!userData) { + return true + } + return this.ShouldCollide(userData, fixture) +};var b2NullContact = function() { + b2Contact.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2NullContact.prototype, b2Contact.prototype); +b2NullContact.prototype._super = b2Contact.prototype; +b2NullContact.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2NullContact.prototype.__varz = function() { +}; +b2NullContact.prototype.Evaluate = function() { +};var b2ContactListener = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactListener.prototype.__constructor = function() { +}; +b2ContactListener.prototype.__varz = function() { +}; +b2ContactListener.b2_defaultListener = new b2ContactListener; +b2ContactListener.prototype.BeginContact = function(contact) { +}; +b2ContactListener.prototype.EndContact = function(contact) { +}; +b2ContactListener.prototype.PreSolve = function(contact, oldManifold) { +}; +b2ContactListener.prototype.PostSolve = function(contact, impulse) { +};var b2Island = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Island.prototype.__constructor = function() { + this.m_bodies = new Array; + this.m_contacts = new Array; + this.m_joints = new Array +}; +b2Island.prototype.__varz = function() { +}; +b2Island.s_impulse = new b2ContactImpulse; +b2Island.prototype.Initialize = function(bodyCapacity, contactCapacity, jointCapacity, allocator, listener, contactSolver) { + var i = 0; + this.m_bodyCapacity = bodyCapacity; + this.m_contactCapacity = contactCapacity; + this.m_jointCapacity = jointCapacity; + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + this.m_allocator = allocator; + this.m_listener = listener; + this.m_contactSolver = contactSolver; + for(i = this.m_bodies.length;i < bodyCapacity;i++) { + this.m_bodies[i] = null + } + for(i = this.m_contacts.length;i < contactCapacity;i++) { + this.m_contacts[i] = null + } + for(i = this.m_joints.length;i < jointCapacity;i++) { + this.m_joints[i] = null + } +}; +b2Island.prototype.Clear = function() { + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0 +}; +b2Island.prototype.Solve = function(step, gravity, allowSleep) { + var i = 0; + var j = 0; + var b; + var joint; + for(i = 0;i < this.m_bodyCount;++i) { + b = this.m_bodies[i]; + if(b.GetType() != b2Body.b2_dynamicBody) { + continue + } + b.m_linearVelocity.x += step.dt * (gravity.x + b.m_invMass * b.m_force.x); + b.m_linearVelocity.y += step.dt * (gravity.y + b.m_invMass * b.m_force.y); + b.m_angularVelocity += step.dt * b.m_invI * b.m_torque; + b.m_linearVelocity.Multiply(b2Math.Clamp(1 - step.dt * b.m_linearDamping, 0, 1)); + b.m_angularVelocity *= b2Math.Clamp(1 - step.dt * b.m_angularDamping, 0, 1) + } + this.m_contactSolver.Initialize(step, this.m_contacts, this.m_contactCount, this.m_allocator); + var contactSolver = this.m_contactSolver; + contactSolver.InitVelocityConstraints(step); + for(i = 0;i < this.m_jointCount;++i) { + joint = this.m_joints[i]; + joint.InitVelocityConstraints(step) + } + for(i = 0;i < step.velocityIterations;++i) { + for(j = 0;j < this.m_jointCount;++j) { + joint = this.m_joints[j]; + joint.SolveVelocityConstraints(step) + } + contactSolver.SolveVelocityConstraints() + } + for(i = 0;i < this.m_jointCount;++i) { + joint = this.m_joints[i]; + joint.FinalizeVelocityConstraints() + } + contactSolver.FinalizeVelocityConstraints(); + for(i = 0;i < this.m_bodyCount;++i) { + b = this.m_bodies[i]; + if(b.GetType() == b2Body.b2_staticBody) { + continue + } + var translationX = step.dt * b.m_linearVelocity.x; + var translationY = step.dt * b.m_linearVelocity.y; + if(translationX * translationX + translationY * translationY > b2Settings.b2_maxTranslationSquared) { + b.m_linearVelocity.Normalize(); + b.m_linearVelocity.x *= b2Settings.b2_maxTranslation * step.inv_dt; + b.m_linearVelocity.y *= b2Settings.b2_maxTranslation * step.inv_dt + } + var rotation = step.dt * b.m_angularVelocity; + if(rotation * rotation > b2Settings.b2_maxRotationSquared) { + if(b.m_angularVelocity < 0) { + b.m_angularVelocity = -b2Settings.b2_maxRotation * step.inv_dt + }else { + b.m_angularVelocity = b2Settings.b2_maxRotation * step.inv_dt + } + } + b.m_sweep.c0.SetV(b.m_sweep.c); + b.m_sweep.a0 = b.m_sweep.a; + b.m_sweep.c.x += step.dt * b.m_linearVelocity.x; + b.m_sweep.c.y += step.dt * b.m_linearVelocity.y; + b.m_sweep.a += step.dt * b.m_angularVelocity; + b.SynchronizeTransform() + } + for(i = 0;i < step.positionIterations;++i) { + var contactsOkay = contactSolver.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + var jointsOkay = true; + for(j = 0;j < this.m_jointCount;++j) { + joint = this.m_joints[j]; + var jointOkay = joint.SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + jointsOkay = jointsOkay && jointOkay + } + if(contactsOkay && jointsOkay) { + break + } + } + this.Report(contactSolver.m_constraints); + if(allowSleep) { + var minSleepTime = Number.MAX_VALUE; + var linTolSqr = b2Settings.b2_linearSleepTolerance * b2Settings.b2_linearSleepTolerance; + var angTolSqr = b2Settings.b2_angularSleepTolerance * b2Settings.b2_angularSleepTolerance; + for(i = 0;i < this.m_bodyCount;++i) { + b = this.m_bodies[i]; + if(b.GetType() == b2Body.b2_staticBody) { + continue + } + if((b.m_flags & b2Body.e_allowSleepFlag) == 0) { + b.m_sleepTime = 0; + minSleepTime = 0 + } + if((b.m_flags & b2Body.e_allowSleepFlag) == 0 || b.m_angularVelocity * b.m_angularVelocity > angTolSqr || b2Math.Dot(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr) { + b.m_sleepTime = 0; + minSleepTime = 0 + }else { + b.m_sleepTime += step.dt; + minSleepTime = b2Math.Min(minSleepTime, b.m_sleepTime) + } + } + if(minSleepTime >= b2Settings.b2_timeToSleep) { + for(i = 0;i < this.m_bodyCount;++i) { + b = this.m_bodies[i]; + b.SetAwake(false) + } + } + } +}; +b2Island.prototype.SolveTOI = function(subStep) { + var i = 0; + var j = 0; + this.m_contactSolver.Initialize(subStep, this.m_contacts, this.m_contactCount, this.m_allocator); + var contactSolver = this.m_contactSolver; + for(i = 0;i < this.m_jointCount;++i) { + this.m_joints[i].InitVelocityConstraints(subStep) + } + for(i = 0;i < subStep.velocityIterations;++i) { + contactSolver.SolveVelocityConstraints(); + for(j = 0;j < this.m_jointCount;++j) { + this.m_joints[j].SolveVelocityConstraints(subStep) + } + } + for(i = 0;i < this.m_bodyCount;++i) { + var b = this.m_bodies[i]; + if(b.GetType() == b2Body.b2_staticBody) { + continue + } + var translationX = subStep.dt * b.m_linearVelocity.x; + var translationY = subStep.dt * b.m_linearVelocity.y; + if(translationX * translationX + translationY * translationY > b2Settings.b2_maxTranslationSquared) { + b.m_linearVelocity.Normalize(); + b.m_linearVelocity.x *= b2Settings.b2_maxTranslation * subStep.inv_dt; + b.m_linearVelocity.y *= b2Settings.b2_maxTranslation * subStep.inv_dt + } + var rotation = subStep.dt * b.m_angularVelocity; + if(rotation * rotation > b2Settings.b2_maxRotationSquared) { + if(b.m_angularVelocity < 0) { + b.m_angularVelocity = -b2Settings.b2_maxRotation * subStep.inv_dt + }else { + b.m_angularVelocity = b2Settings.b2_maxRotation * subStep.inv_dt + } + } + b.m_sweep.c0.SetV(b.m_sweep.c); + b.m_sweep.a0 = b.m_sweep.a; + b.m_sweep.c.x += subStep.dt * b.m_linearVelocity.x; + b.m_sweep.c.y += subStep.dt * b.m_linearVelocity.y; + b.m_sweep.a += subStep.dt * b.m_angularVelocity; + b.SynchronizeTransform() + } + var k_toiBaumgarte = 0.75; + for(i = 0;i < subStep.positionIterations;++i) { + var contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte); + var jointsOkay = true; + for(j = 0;j < this.m_jointCount;++j) { + var jointOkay = this.m_joints[j].SolvePositionConstraints(b2Settings.b2_contactBaumgarte); + jointsOkay = jointsOkay && jointOkay + } + if(contactsOkay && jointsOkay) { + break + } + } + this.Report(contactSolver.m_constraints) +}; +b2Island.prototype.Report = function(constraints) { + if(this.m_listener == null) { + return + } + for(var i = 0;i < this.m_contactCount;++i) { + var c = this.m_contacts[i]; + var cc = constraints[i]; + for(var j = 0;j < cc.pointCount;++j) { + b2Island.s_impulse.normalImpulses[j] = cc.points[j].normalImpulse; + b2Island.s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse + } + this.m_listener.PostSolve(c, b2Island.s_impulse) + } +}; +b2Island.prototype.AddBody = function(body) { + body.m_islandIndex = this.m_bodyCount; + this.m_bodies[this.m_bodyCount++] = body +}; +b2Island.prototype.AddContact = function(contact) { + this.m_contacts[this.m_contactCount++] = contact +}; +b2Island.prototype.AddJoint = function(joint) { + this.m_joints[this.m_jointCount++] = joint +}; +b2Island.prototype.m_allocator = null; +b2Island.prototype.m_listener = null; +b2Island.prototype.m_contactSolver = null; +b2Island.prototype.m_bodies = null; +b2Island.prototype.m_contacts = null; +b2Island.prototype.m_joints = null; +b2Island.prototype.m_bodyCount = 0; +b2Island.prototype.m_jointCount = 0; +b2Island.prototype.m_contactCount = 0; +b2Island.prototype.m_bodyCapacity = 0; +b2Island.prototype.m_contactCapacity = 0; +b2Island.prototype.m_jointCapacity = 0;var b2PolyAndEdgeContact = function() { + b2Contact.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PolyAndEdgeContact.prototype, b2Contact.prototype); +b2PolyAndEdgeContact.prototype._super = b2Contact.prototype; +b2PolyAndEdgeContact.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2PolyAndEdgeContact.prototype.__varz = function() { +}; +b2PolyAndEdgeContact.Create = function(allocator) { + return new b2PolyAndEdgeContact +}; +b2PolyAndEdgeContact.Destroy = function(contact, allocator) { +}; +b2PolyAndEdgeContact.prototype.Evaluate = function() { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + this.b2CollidePolyAndEdge(this.m_manifold, this.m_fixtureA.GetShape(), bA.m_xf, this.m_fixtureB.GetShape(), bB.m_xf) +}; +b2PolyAndEdgeContact.prototype.b2CollidePolyAndEdge = function(manifold, polygon, xf1, edge, xf2) { +}; +b2PolyAndEdgeContact.prototype.Reset = function(fixtureA, fixtureB) { + this._super.Reset.apply(this, [fixtureA, fixtureB]); + b2Settings.b2Assert(fixtureA.GetType() == b2Shape.e_polygonShape); + b2Settings.b2Assert(fixtureB.GetType() == b2Shape.e_edgeShape) +};var b2Collision = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2Collision.prototype.__constructor = function() { +}; +b2Collision.prototype.__varz = function() { +}; +b2Collision.MakeClipPointVector = function() { + var r = new Array(2); + r[0] = new ClipVertex; + r[1] = new ClipVertex; + return r +}; +b2Collision.ClipSegmentToLine = function(vOut, vIn, normal, offset) { + var cv; + var numOut = 0; + cv = vIn[0]; + var vIn0 = cv.v; + cv = vIn[1]; + var vIn1 = cv.v; + var distance0 = normal.x * vIn0.x + normal.y * vIn0.y - offset; + var distance1 = normal.x * vIn1.x + normal.y * vIn1.y - offset; + if(distance0 <= 0) { + vOut[numOut++].Set(vIn[0]) + } + if(distance1 <= 0) { + vOut[numOut++].Set(vIn[1]) + } + if(distance0 * distance1 < 0) { + var interp = distance0 / (distance0 - distance1); + cv = vOut[numOut]; + var tVec = cv.v; + tVec.x = vIn0.x + interp * (vIn1.x - vIn0.x); + tVec.y = vIn0.y + interp * (vIn1.y - vIn0.y); + cv = vOut[numOut]; + var cv2; + if(distance0 > 0) { + cv2 = vIn[0]; + cv.id = cv2.id + }else { + cv2 = vIn[1]; + cv.id = cv2.id + } + ++numOut + } + return numOut +}; +b2Collision.EdgeSeparation = function(poly1, xf1, edge1, poly2, xf2) { + var count1 = poly1.m_vertexCount; + var vertices1 = poly1.m_vertices; + var normals1 = poly1.m_normals; + var count2 = poly2.m_vertexCount; + var vertices2 = poly2.m_vertices; + var tMat; + var tVec; + tMat = xf1.R; + tVec = normals1[edge1]; + var normal1WorldX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + var normal1WorldY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xf2.R; + var normal1X = tMat.col1.x * normal1WorldX + tMat.col1.y * normal1WorldY; + var normal1Y = tMat.col2.x * normal1WorldX + tMat.col2.y * normal1WorldY; + var index = 0; + var minDot = Number.MAX_VALUE; + for(var i = 0;i < count2;++i) { + tVec = vertices2[i]; + var dot = tVec.x * normal1X + tVec.y * normal1Y; + if(dot < minDot) { + minDot = dot; + index = i + } + } + tVec = vertices1[edge1]; + tMat = xf1.R; + var v1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var v1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tVec = vertices2[index]; + tMat = xf2.R; + var v2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var v2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + v2X -= v1X; + v2Y -= v1Y; + var separation = v2X * normal1WorldX + v2Y * normal1WorldY; + return separation +}; +b2Collision.FindMaxSeparation = function(edgeIndex, poly1, xf1, poly2, xf2) { + var count1 = poly1.m_vertexCount; + var normals1 = poly1.m_normals; + var tVec; + var tMat; + tMat = xf2.R; + tVec = poly2.m_centroid; + var dX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var dY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf1.R; + tVec = poly1.m_centroid; + dX -= xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + dY -= xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var dLocal1X = dX * xf1.R.col1.x + dY * xf1.R.col1.y; + var dLocal1Y = dX * xf1.R.col2.x + dY * xf1.R.col2.y; + var edge = 0; + var maxDot = -Number.MAX_VALUE; + for(var i = 0;i < count1;++i) { + tVec = normals1[i]; + var dot = tVec.x * dLocal1X + tVec.y * dLocal1Y; + if(dot > maxDot) { + maxDot = dot; + edge = i + } + } + var s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); + var prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; + var sPrev = b2Collision.EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); + var nextEdge = edge + 1 < count1 ? edge + 1 : 0; + var sNext = b2Collision.EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); + var bestEdge = 0; + var bestSeparation; + var increment = 0; + if(sPrev > s && sPrev > sNext) { + increment = -1; + bestEdge = prevEdge; + bestSeparation = sPrev + }else { + if(sNext > s) { + increment = 1; + bestEdge = nextEdge; + bestSeparation = sNext + }else { + edgeIndex[0] = edge; + return s + } + } + while(true) { + if(increment == -1) { + edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1 + }else { + edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0 + } + s = b2Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2); + if(s > bestSeparation) { + bestEdge = edge; + bestSeparation = s + }else { + break + } + } + edgeIndex[0] = bestEdge; + return bestSeparation +}; +b2Collision.FindIncidentEdge = function(c, poly1, xf1, edge1, poly2, xf2) { + var count1 = poly1.m_vertexCount; + var normals1 = poly1.m_normals; + var count2 = poly2.m_vertexCount; + var vertices2 = poly2.m_vertices; + var normals2 = poly2.m_normals; + var tMat; + var tVec; + tMat = xf1.R; + tVec = normals1[edge1]; + var normal1X = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; + var normal1Y = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; + tMat = xf2.R; + var tX = tMat.col1.x * normal1X + tMat.col1.y * normal1Y; + normal1Y = tMat.col2.x * normal1X + tMat.col2.y * normal1Y; + normal1X = tX; + var index = 0; + var minDot = Number.MAX_VALUE; + for(var i = 0;i < count2;++i) { + tVec = normals2[i]; + var dot = normal1X * tVec.x + normal1Y * tVec.y; + if(dot < minDot) { + minDot = dot; + index = i + } + } + var tClip; + var i1 = index; + var i2 = i1 + 1 < count2 ? i1 + 1 : 0; + tClip = c[0]; + tVec = vertices2[i1]; + tMat = xf2.R; + tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tClip.id.features.referenceEdge = edge1; + tClip.id.features.incidentEdge = i1; + tClip.id.features.incidentVertex = 0; + tClip = c[1]; + tVec = vertices2[i2]; + tMat = xf2.R; + tClip.v.x = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + tClip.v.y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tClip.id.features.referenceEdge = edge1; + tClip.id.features.incidentEdge = i2; + tClip.id.features.incidentVertex = 1 +}; +b2Collision.CollidePolygons = function(manifold, polyA, xfA, polyB, xfB) { + var cv; + manifold.m_pointCount = 0; + var totalRadius = polyA.m_radius + polyB.m_radius; + var edgeA = 0; + b2Collision.s_edgeAO[0] = edgeA; + var separationA = b2Collision.FindMaxSeparation(b2Collision.s_edgeAO, polyA, xfA, polyB, xfB); + edgeA = b2Collision.s_edgeAO[0]; + if(separationA > totalRadius) { + return + } + var edgeB = 0; + b2Collision.s_edgeBO[0] = edgeB; + var separationB = b2Collision.FindMaxSeparation(b2Collision.s_edgeBO, polyB, xfB, polyA, xfA); + edgeB = b2Collision.s_edgeBO[0]; + if(separationB > totalRadius) { + return + } + var poly1; + var poly2; + var xf1; + var xf2; + var edge1 = 0; + var flip = 0; + var k_relativeTol = 0.98; + var k_absoluteTol = 0.0010; + var tMat; + if(separationB > k_relativeTol * separationA + k_absoluteTol) { + poly1 = polyB; + poly2 = polyA; + xf1 = xfB; + xf2 = xfA; + edge1 = edgeB; + manifold.m_type = b2Manifold.e_faceB; + flip = 1 + }else { + poly1 = polyA; + poly2 = polyB; + xf1 = xfA; + xf2 = xfB; + edge1 = edgeA; + manifold.m_type = b2Manifold.e_faceA; + flip = 0 + } + var incidentEdge = b2Collision.s_incidentEdge; + b2Collision.FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); + var count1 = poly1.m_vertexCount; + var vertices1 = poly1.m_vertices; + var local_v11 = vertices1[edge1]; + var local_v12; + if(edge1 + 1 < count1) { + local_v12 = vertices1[parseInt(edge1 + 1)] + }else { + local_v12 = vertices1[0] + } + var localTangent = b2Collision.s_localTangent; + localTangent.Set(local_v12.x - local_v11.x, local_v12.y - local_v11.y); + localTangent.Normalize(); + var localNormal = b2Collision.s_localNormal; + localNormal.x = localTangent.y; + localNormal.y = -localTangent.x; + var planePoint = b2Collision.s_planePoint; + planePoint.Set(0.5 * (local_v11.x + local_v12.x), 0.5 * (local_v11.y + local_v12.y)); + var tangent = b2Collision.s_tangent; + tMat = xf1.R; + tangent.x = tMat.col1.x * localTangent.x + tMat.col2.x * localTangent.y; + tangent.y = tMat.col1.y * localTangent.x + tMat.col2.y * localTangent.y; + var tangent2 = b2Collision.s_tangent2; + tangent2.x = -tangent.x; + tangent2.y = -tangent.y; + var normal = b2Collision.s_normal; + normal.x = tangent.y; + normal.y = -tangent.x; + var v11 = b2Collision.s_v11; + var v12 = b2Collision.s_v12; + v11.x = xf1.position.x + (tMat.col1.x * local_v11.x + tMat.col2.x * local_v11.y); + v11.y = xf1.position.y + (tMat.col1.y * local_v11.x + tMat.col2.y * local_v11.y); + v12.x = xf1.position.x + (tMat.col1.x * local_v12.x + tMat.col2.x * local_v12.y); + v12.y = xf1.position.y + (tMat.col1.y * local_v12.x + tMat.col2.y * local_v12.y); + var frontOffset = normal.x * v11.x + normal.y * v11.y; + var sideOffset1 = -tangent.x * v11.x - tangent.y * v11.y + totalRadius; + var sideOffset2 = tangent.x * v12.x + tangent.y * v12.y + totalRadius; + var clipPoints1 = b2Collision.s_clipPoints1; + var clipPoints2 = b2Collision.s_clipPoints2; + var np = 0; + np = b2Collision.ClipSegmentToLine(clipPoints1, incidentEdge, tangent2, sideOffset1); + if(np < 2) { + return + } + np = b2Collision.ClipSegmentToLine(clipPoints2, clipPoints1, tangent, sideOffset2); + if(np < 2) { + return + } + manifold.m_localPlaneNormal.SetV(localNormal); + manifold.m_localPoint.SetV(planePoint); + var pointCount = 0; + for(var i = 0;i < b2Settings.b2_maxManifoldPoints;++i) { + cv = clipPoints2[i]; + var separation = normal.x * cv.v.x + normal.y * cv.v.y - frontOffset; + if(separation <= totalRadius) { + var cp = manifold.m_points[pointCount]; + tMat = xf2.R; + var tX = cv.v.x - xf2.position.x; + var tY = cv.v.y - xf2.position.y; + cp.m_localPoint.x = tX * tMat.col1.x + tY * tMat.col1.y; + cp.m_localPoint.y = tX * tMat.col2.x + tY * tMat.col2.y; + cp.m_id.Set(cv.id); + cp.m_id.features.flip = flip; + ++pointCount + } + } + manifold.m_pointCount = pointCount +}; +b2Collision.CollideCircles = function(manifold, circle1, xf1, circle2, xf2) { + manifold.m_pointCount = 0; + var tMat; + var tVec; + tMat = xf1.R; + tVec = circle1.m_p; + var p1X = xf1.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p1Y = xf1.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + tMat = xf2.R; + tVec = circle2.m_p; + var p2X = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var p2Y = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + var dX = p2X - p1X; + var dY = p2Y - p1Y; + var distSqr = dX * dX + dY * dY; + var radius = circle1.m_radius + circle2.m_radius; + if(distSqr > radius * radius) { + return + } + manifold.m_type = b2Manifold.e_circles; + manifold.m_localPoint.SetV(circle1.m_p); + manifold.m_localPlaneNormal.SetZero(); + manifold.m_pointCount = 1; + manifold.m_points[0].m_localPoint.SetV(circle2.m_p); + manifold.m_points[0].m_id.key = 0 +}; +b2Collision.CollidePolygonAndCircle = function(manifold, polygon, xf1, circle, xf2) { + manifold.m_pointCount = 0; + var tPoint; + var dX; + var dY; + var positionX; + var positionY; + var tVec; + var tMat; + tMat = xf2.R; + tVec = circle.m_p; + var cX = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); + var cY = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); + dX = cX - xf1.position.x; + dY = cY - xf1.position.y; + tMat = xf1.R; + var cLocalX = dX * tMat.col1.x + dY * tMat.col1.y; + var cLocalY = dX * tMat.col2.x + dY * tMat.col2.y; + var dist; + var normalIndex = 0; + var separation = -Number.MAX_VALUE; + var radius = polygon.m_radius + circle.m_radius; + var vertexCount = polygon.m_vertexCount; + var vertices = polygon.m_vertices; + var normals = polygon.m_normals; + for(var i = 0;i < vertexCount;++i) { + tVec = vertices[i]; + dX = cLocalX - tVec.x; + dY = cLocalY - tVec.y; + tVec = normals[i]; + var s = tVec.x * dX + tVec.y * dY; + if(s > radius) { + return + } + if(s > separation) { + separation = s; + normalIndex = i + } + } + var vertIndex1 = normalIndex; + var vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; + var v1 = vertices[vertIndex1]; + var v2 = vertices[vertIndex2]; + if(separation < Number.MIN_VALUE) { + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.SetV(normals[normalIndex]); + manifold.m_localPoint.x = 0.5 * (v1.x + v2.x); + manifold.m_localPoint.y = 0.5 * (v1.y + v2.y); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0; + return + } + var u1 = (cLocalX - v1.x) * (v2.x - v1.x) + (cLocalY - v1.y) * (v2.y - v1.y); + var u2 = (cLocalX - v2.x) * (v1.x - v2.x) + (cLocalY - v2.y) * (v1.y - v2.y); + if(u1 <= 0) { + if((cLocalX - v1.x) * (cLocalX - v1.x) + (cLocalY - v1.y) * (cLocalY - v1.y) > radius * radius) { + return + } + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.x = cLocalX - v1.x; + manifold.m_localPlaneNormal.y = cLocalY - v1.y; + manifold.m_localPlaneNormal.Normalize(); + manifold.m_localPoint.SetV(v1); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0 + }else { + if(u2 <= 0) { + if((cLocalX - v2.x) * (cLocalX - v2.x) + (cLocalY - v2.y) * (cLocalY - v2.y) > radius * radius) { + return + } + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.x = cLocalX - v2.x; + manifold.m_localPlaneNormal.y = cLocalY - v2.y; + manifold.m_localPlaneNormal.Normalize(); + manifold.m_localPoint.SetV(v2); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0 + }else { + var faceCenterX = 0.5 * (v1.x + v2.x); + var faceCenterY = 0.5 * (v1.y + v2.y); + separation = (cLocalX - faceCenterX) * normals[vertIndex1].x + (cLocalY - faceCenterY) * normals[vertIndex1].y; + if(separation > radius) { + return + } + manifold.m_pointCount = 1; + manifold.m_type = b2Manifold.e_faceA; + manifold.m_localPlaneNormal.x = normals[vertIndex1].x; + manifold.m_localPlaneNormal.y = normals[vertIndex1].y; + manifold.m_localPlaneNormal.Normalize(); + manifold.m_localPoint.Set(faceCenterX, faceCenterY); + manifold.m_points[0].m_localPoint.SetV(circle.m_p); + manifold.m_points[0].m_id.key = 0 + } + } +}; +b2Collision.TestOverlap = function(a, b) { + var t1 = b.lowerBound; + var t2 = a.upperBound; + var d1X = t1.x - t2.x; + var d1Y = t1.y - t2.y; + t1 = a.lowerBound; + t2 = b.upperBound; + var d2X = t1.x - t2.x; + var d2Y = t1.y - t2.y; + if(d1X > 0 || d1Y > 0) { + return false + } + if(d2X > 0 || d2Y > 0) { + return false + } + return true +}; +b2Collision.b2_nullFeature = 255; +b2Collision.s_incidentEdge = b2Collision.MakeClipPointVector(); +b2Collision.s_clipPoints1 = b2Collision.MakeClipPointVector(); +b2Collision.s_clipPoints2 = b2Collision.MakeClipPointVector(); +b2Collision.s_edgeAO = new Array(1); +b2Collision.s_edgeBO = new Array(1); +b2Collision.s_localTangent = new b2Vec2; +b2Collision.s_localNormal = new b2Vec2; +b2Collision.s_planePoint = new b2Vec2; +b2Collision.s_normal = new b2Vec2; +b2Collision.s_tangent = new b2Vec2; +b2Collision.s_tangent2 = new b2Vec2; +b2Collision.s_v11 = new b2Vec2; +b2Collision.s_v12 = new b2Vec2; +b2Collision.b2CollidePolyTempVec = new b2Vec2;var b2PolyAndCircleContact = function() { + b2Contact.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2PolyAndCircleContact.prototype, b2Contact.prototype); +b2PolyAndCircleContact.prototype._super = b2Contact.prototype; +b2PolyAndCircleContact.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2PolyAndCircleContact.prototype.__varz = function() { +}; +b2PolyAndCircleContact.Create = function(allocator) { + return new b2PolyAndCircleContact +}; +b2PolyAndCircleContact.Destroy = function(contact, allocator) { +}; +b2PolyAndCircleContact.prototype.Evaluate = function() { + var bA = this.m_fixtureA.m_body; + var bB = this.m_fixtureB.m_body; + b2Collision.CollidePolygonAndCircle(this.m_manifold, this.m_fixtureA.GetShape(), bA.m_xf, this.m_fixtureB.GetShape(), bB.m_xf) +}; +b2PolyAndCircleContact.prototype.Reset = function(fixtureA, fixtureB) { + this._super.Reset.apply(this, [fixtureA, fixtureB]); + b2Settings.b2Assert(fixtureA.GetType() == b2Shape.e_polygonShape); + b2Settings.b2Assert(fixtureB.GetType() == b2Shape.e_circleShape) +};var b2ContactPoint = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactPoint.prototype.__constructor = function() { +}; +b2ContactPoint.prototype.__varz = function() { + this.position = new b2Vec2; + this.velocity = new b2Vec2; + this.normal = new b2Vec2; + this.id = new b2ContactID +}; +b2ContactPoint.prototype.shape1 = null; +b2ContactPoint.prototype.shape2 = null; +b2ContactPoint.prototype.position = new b2Vec2; +b2ContactPoint.prototype.velocity = new b2Vec2; +b2ContactPoint.prototype.normal = new b2Vec2; +b2ContactPoint.prototype.separation = null; +b2ContactPoint.prototype.friction = null; +b2ContactPoint.prototype.restitution = null; +b2ContactPoint.prototype.id = new b2ContactID;var b2CircleContact = function() { + b2Contact.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2CircleContact.prototype, b2Contact.prototype); +b2CircleContact.prototype._super = b2Contact.prototype; +b2CircleContact.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2CircleContact.prototype.__varz = function() { +}; +b2CircleContact.Create = function(allocator) { + return new b2CircleContact +}; +b2CircleContact.Destroy = function(contact, allocator) { +}; +b2CircleContact.prototype.Evaluate = function() { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + b2Collision.CollideCircles(this.m_manifold, this.m_fixtureA.GetShape(), bA.m_xf, this.m_fixtureB.GetShape(), bB.m_xf) +}; +b2CircleContact.prototype.Reset = function(fixtureA, fixtureB) { + this._super.Reset.apply(this, [fixtureA, fixtureB]) +};var b2EdgeAndCircleContact = function() { + b2Contact.prototype.__varz.call(this); + this.__varz(); + this.__constructor.apply(this, arguments) +}; +extend(b2EdgeAndCircleContact.prototype, b2Contact.prototype); +b2EdgeAndCircleContact.prototype._super = b2Contact.prototype; +b2EdgeAndCircleContact.prototype.__constructor = function() { + this._super.__constructor.apply(this, arguments) +}; +b2EdgeAndCircleContact.prototype.__varz = function() { +}; +b2EdgeAndCircleContact.Create = function(allocator) { + return new b2EdgeAndCircleContact +}; +b2EdgeAndCircleContact.Destroy = function(contact, allocator) { +}; +b2EdgeAndCircleContact.prototype.Evaluate = function() { + var bA = this.m_fixtureA.GetBody(); + var bB = this.m_fixtureB.GetBody(); + this.b2CollideEdgeAndCircle(this.m_manifold, this.m_fixtureA.GetShape(), bA.m_xf, this.m_fixtureB.GetShape(), bB.m_xf) +}; +b2EdgeAndCircleContact.prototype.b2CollideEdgeAndCircle = function(manifold, edge, xf1, circle, xf2) { +}; +b2EdgeAndCircleContact.prototype.Reset = function(fixtureA, fixtureB) { + this._super.Reset.apply(this, [fixtureA, fixtureB]) +};var b2ContactManager = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2ContactManager.prototype.__constructor = function() { + this.m_world = null; + this.m_contactCount = 0; + this.m_contactFilter = b2ContactFilter.b2_defaultFilter; + this.m_contactListener = b2ContactListener.b2_defaultListener; + this.m_contactFactory = new b2ContactFactory(this.m_allocator); + this.m_broadPhase = new b2DynamicTreeBroadPhase +}; +b2ContactManager.prototype.__varz = function() { +}; +b2ContactManager.s_evalCP = new b2ContactPoint; +b2ContactManager.prototype.AddPair = function(proxyUserDataA, proxyUserDataB) { + var fixtureA = proxyUserDataA; + var fixtureB = proxyUserDataB; + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if(bodyA == bodyB) { + return + } + var edge = bodyB.GetContactList(); + while(edge) { + if(edge.other == bodyA) { + var fA = edge.contact.GetFixtureA(); + var fB = edge.contact.GetFixtureB(); + if(fA == fixtureA && fB == fixtureB) { + return + } + if(fA == fixtureB && fB == fixtureA) { + return + } + } + edge = edge.next + } + if(bodyB.ShouldCollide(bodyA) == false) { + return + } + if(this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { + return + } + var c = this.m_contactFactory.Create(fixtureA, fixtureB); + fixtureA = c.GetFixtureA(); + fixtureB = c.GetFixtureB(); + bodyA = fixtureA.m_body; + bodyB = fixtureB.m_body; + c.m_prev = null; + c.m_next = this.m_world.m_contactList; + if(this.m_world.m_contactList != null) { + this.m_world.m_contactList.m_prev = c + } + this.m_world.m_contactList = c; + c.m_nodeA.contact = c; + c.m_nodeA.other = bodyB; + c.m_nodeA.prev = null; + c.m_nodeA.next = bodyA.m_contactList; + if(bodyA.m_contactList != null) { + bodyA.m_contactList.prev = c.m_nodeA + } + bodyA.m_contactList = c.m_nodeA; + c.m_nodeB.contact = c; + c.m_nodeB.other = bodyA; + c.m_nodeB.prev = null; + c.m_nodeB.next = bodyB.m_contactList; + if(bodyB.m_contactList != null) { + bodyB.m_contactList.prev = c.m_nodeB + } + bodyB.m_contactList = c.m_nodeB; + ++this.m_world.m_contactCount; + return +}; +b2ContactManager.prototype.FindNewContacts = function() { + var that = this; + this.m_broadPhase.UpdatePairs(function(a, b) { + return that.AddPair(a, b) + }) +}; +b2ContactManager.prototype.Destroy = function(c) { + var fixtureA = c.GetFixtureA(); + var fixtureB = c.GetFixtureB(); + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if(c.IsTouching()) { + this.m_contactListener.EndContact(c) + } + if(c.m_prev) { + c.m_prev.m_next = c.m_next + } + if(c.m_next) { + c.m_next.m_prev = c.m_prev + } + if(c == this.m_world.m_contactList) { + this.m_world.m_contactList = c.m_next + } + if(c.m_nodeA.prev) { + c.m_nodeA.prev.next = c.m_nodeA.next + } + if(c.m_nodeA.next) { + c.m_nodeA.next.prev = c.m_nodeA.prev + } + if(c.m_nodeA == bodyA.m_contactList) { + bodyA.m_contactList = c.m_nodeA.next + } + if(c.m_nodeB.prev) { + c.m_nodeB.prev.next = c.m_nodeB.next + } + if(c.m_nodeB.next) { + c.m_nodeB.next.prev = c.m_nodeB.prev + } + if(c.m_nodeB == bodyB.m_contactList) { + bodyB.m_contactList = c.m_nodeB.next + } + this.m_contactFactory.Destroy(c); + --this.m_contactCount +}; +b2ContactManager.prototype.Collide = function() { + var c = this.m_world.m_contactList; + while(c) { + var fixtureA = c.GetFixtureA(); + var fixtureB = c.GetFixtureB(); + var bodyA = fixtureA.GetBody(); + var bodyB = fixtureB.GetBody(); + if(bodyA.IsAwake() == false && bodyB.IsAwake() == false) { + c = c.GetNext(); + continue + } + if(c.m_flags & b2Contact.e_filterFlag) { + if(bodyB.ShouldCollide(bodyA) == false) { + var cNuke = c; + c = cNuke.GetNext(); + this.Destroy(cNuke); + continue + } + if(this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) { + cNuke = c; + c = cNuke.GetNext(); + this.Destroy(cNuke); + continue + } + c.m_flags &= ~b2Contact.e_filterFlag + } + var proxyA = fixtureA.m_proxy; + var proxyB = fixtureB.m_proxy; + var overlap = this.m_broadPhase.TestOverlap(proxyA, proxyB); + if(overlap == false) { + cNuke = c; + c = cNuke.GetNext(); + this.Destroy(cNuke); + continue + } + c.Update(this.m_contactListener); + c = c.GetNext() + } +}; +b2ContactManager.prototype.m_world = null; +b2ContactManager.prototype.m_broadPhase = null; +b2ContactManager.prototype.m_contactList = null; +b2ContactManager.prototype.m_contactCount = 0; +b2ContactManager.prototype.m_contactFilter = null; +b2ContactManager.prototype.m_contactListener = null; +b2ContactManager.prototype.m_contactFactory = null; +b2ContactManager.prototype.m_allocator = null;var b2World = function() { + this.__varz(); + this.__constructor.apply(this, arguments) +}; +b2World.prototype.__constructor = function(gravity, doSleep) { + this.m_destructionListener = null; + this.m_debugDraw = null; + this.m_bodyList = null; + this.m_contactList = null; + this.m_jointList = null; + this.m_controllerList = null; + this.m_bodyCount = 0; + this.m_contactCount = 0; + this.m_jointCount = 0; + this.m_controllerCount = 0; + b2World.m_warmStarting = true; + b2World.m_continuousPhysics = true; + this.m_allowSleep = doSleep; + this.m_gravity = gravity; + this.m_inv_dt0 = 0; + this.m_contactManager.m_world = this; + var bd = new b2BodyDef; + this.m_groundBody = this.CreateBody(bd) +}; +b2World.prototype.__varz = function() { + this.s_stack = new Array; + this.m_contactManager = new b2ContactManager; + this.m_contactSolver = new b2ContactSolver; + this.m_island = new b2Island +}; +b2World.s_timestep2 = new b2TimeStep; +b2World.s_backupA = new b2Sweep; +b2World.s_backupB = new b2Sweep; +b2World.s_timestep = new b2TimeStep; +b2World.s_queue = new Array; +b2World.e_newFixture = 1; +b2World.e_locked = 2; +b2World.s_xf = new b2Transform; +b2World.s_jointColor = new b2Color(0.5, 0.8, 0.8); +b2World.m_warmStarting = null; +b2World.m_continuousPhysics = null; +b2World.prototype.Solve = function(step) { + var b; + for(var controller = this.m_controllerList;controller;controller = controller.m_next) { + controller.Step(step) + } + var island = this.m_island; + island.Initialize(this.m_bodyCount, this.m_contactCount, this.m_jointCount, null, this.m_contactManager.m_contactListener, this.m_contactSolver); + for(b = this.m_bodyList;b;b = b.m_next) { + b.m_flags &= ~b2Body.e_islandFlag + } + for(var c = this.m_contactList;c;c = c.m_next) { + c.m_flags &= ~b2Contact.e_islandFlag + } + for(var j = this.m_jointList;j;j = j.m_next) { + j.m_islandFlag = false + } + var stackSize = this.m_bodyCount; + var stack = this.s_stack; + for(var seed = this.m_bodyList;seed;seed = seed.m_next) { + if(seed.m_flags & b2Body.e_islandFlag) { + continue + } + if(seed.IsAwake() == false || seed.IsActive() == false) { + continue + } + if(seed.GetType() == b2Body.b2_staticBody) { + continue + } + island.Clear(); + var stackCount = 0; + stack[stackCount++] = seed; + seed.m_flags |= b2Body.e_islandFlag; + while(stackCount > 0) { + b = stack[--stackCount]; + island.AddBody(b); + if(b.IsAwake() == false) { + b.SetAwake(true) + } + if(b.GetType() == b2Body.b2_staticBody) { + continue + } + var other; + for(var ce = b.m_contactList;ce;ce = ce.next) { + if(ce.contact.m_flags & b2Contact.e_islandFlag) { + continue + } + if(ce.contact.IsSensor() == true || ce.contact.IsEnabled() == false || ce.contact.IsTouching() == false) { + continue + } + island.AddContact(ce.contact); + ce.contact.m_flags |= b2Contact.e_islandFlag; + other = ce.other; + if(other.m_flags & b2Body.e_islandFlag) { + continue + } + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag + } + for(var jn = b.m_jointList;jn;jn = jn.next) { + if(jn.joint.m_islandFlag == true) { + continue + } + other = jn.other; + if(other.IsActive() == false) { + continue + } + island.AddJoint(jn.joint); + jn.joint.m_islandFlag = true; + if(other.m_flags & b2Body.e_islandFlag) { + continue + } + stack[stackCount++] = other; + other.m_flags |= b2Body.e_islandFlag + } + } + island.Solve(step, this.m_gravity, this.m_allowSleep); + for(var i = 0;i < island.m_bodyCount;++i) { + b = island.m_bodies[i]; + if(b.GetType() == b2Body.b2_staticBody) { + b.m_flags &= ~b2Body.e_islandFlag + } + } + } + for(i = 0;i < stack.length;++i) { + if(!stack[i]) { + break + } + stack[i] = null + } + for(b = this.m_bodyList;b;b = b.m_next) { + if(b.IsAwake() == false || b.IsActive() == false) { + continue + } + if(b.GetType() == b2Body.b2_staticBody) { + continue + } + b.SynchronizeFixtures() + } + this.m_contactManager.FindNewContacts() +}; +b2World.prototype.SolveTOI = function(step) { + var b; + var fA; + var fB; + var bA; + var bB; + var cEdge; + var j; + var island = this.m_island; + island.Initialize(this.m_bodyCount, b2Settings.b2_maxTOIContactsPerIsland, b2Settings.b2_maxTOIJointsPerIsland, null, this.m_contactManager.m_contactListener, this.m_contactSolver); + var queue = b2World.s_queue; + for(b = this.m_bodyList;b;b = b.m_next) { + b.m_flags &= ~b2Body.e_islandFlag; + b.m_sweep.t0 = 0 + } + var c; + for(c = this.m_contactList;c;c = c.m_next) { + c.m_flags &= ~(b2Contact.e_toiFlag | b2Contact.e_islandFlag) + } + for(j = this.m_jointList;j;j = j.m_next) { + j.m_islandFlag = false + } + for(;;) { + var minContact = null; + var minTOI = 1; + for(c = this.m_contactList;c;c = c.m_next) { + if(c.IsSensor() == true || c.IsEnabled() == false || c.IsContinuous() == false) { + continue + } + var toi = 1; + if(c.m_flags & b2Contact.e_toiFlag) { + toi = c.m_toi + }else { + fA = c.m_fixtureA; + fB = c.m_fixtureB; + bA = fA.m_body; + bB = fB.m_body; + if((bA.GetType() != b2Body.b2_dynamicBody || bA.IsAwake() == false) && (bB.GetType() != b2Body.b2_dynamicBody || bB.IsAwake() == false)) { + continue + } + var t0 = bA.m_sweep.t0; + if(bA.m_sweep.t0 < bB.m_sweep.t0) { + t0 = bB.m_sweep.t0; + bA.m_sweep.Advance(t0) + }else { + if(bB.m_sweep.t0 < bA.m_sweep.t0) { + t0 = bA.m_sweep.t0; + bB.m_sweep.Advance(t0) + } + } + toi = c.ComputeTOI(bA.m_sweep, bB.m_sweep); + b2Settings.b2Assert(0 <= toi && toi <= 1); + if(toi > 0 && toi < 1) { + toi = (1 - toi) * t0 + toi; + if(toi > 1) { + toi = 1 + } + } + c.m_toi = toi; + c.m_flags |= b2Contact.e_toiFlag + } + if(Number.MIN_VALUE < toi && toi < minTOI) { + minContact = c; + minTOI = toi + } + } + if(minContact == null || 1 - 100 * Number.MIN_VALUE < minTOI) { + break + } + fA = minContact.m_fixtureA; + fB = minContact.m_fixtureB; + bA = fA.m_body; + bB = fB.m_body; + b2World.s_backupA.Set(bA.m_sweep); + b2World.s_backupB.Set(bB.m_sweep); + bA.Advance(minTOI); + bB.Advance(minTOI); + minContact.Update(this.m_contactManager.m_contactListener); + minContact.m_flags &= ~b2Contact.e_toiFlag; + if(minContact.IsSensor() == true || minContact.IsEnabled() == false) { + bA.m_sweep.Set(b2World.s_backupA); + bB.m_sweep.Set(b2World.s_backupB); + bA.SynchronizeTransform(); + bB.SynchronizeTransform(); + continue + } + if(minContact.IsTouching() == false) { + continue + } + var seed = bA; + if(seed.GetType() != b2Body.b2_dynamicBody) { + seed = bB + } + island.Clear(); + var queueStart = 0; + var queueSize = 0; + queue[queueStart + queueSize++] = seed; + seed.m_flags |= b2Body.e_islandFlag; + while(queueSize > 0) { + b = queue[queueStart++]; + --queueSize; + island.AddBody(b); + if(b.IsAwake() == false) { + b.SetAwake(true) + } + if(b.GetType() != b2Body.b2_dynamicBody) { + continue + } + for(cEdge = b.m_contactList;cEdge;cEdge = cEdge.next) { + if(island.m_contactCount == island.m_contactCapacity) { + break + } + if(cEdge.contact.m_flags & b2Contact.e_islandFlag) { + continue + } + if(cEdge.contact.IsSensor() == true || cEdge.contact.IsEnabled() == false || cEdge.contact.IsTouching() == false) { + continue + } + island.AddContact(cEdge.contact); + cEdge.contact.m_flags |= b2Contact.e_islandFlag; + var other = cEdge.other; + if(other.m_flags & b2Body.e_islandFlag) { + continue + } + if(other.GetType() != b2Body.b2_staticBody) { + other.Advance(minTOI); + other.SetAwake(true) + } + queue[queueStart + queueSize] = other; + ++queueSize; + other.m_flags |= b2Body.e_islandFlag + } + for(var jEdge = b.m_jointList;jEdge;jEdge = jEdge.next) { + if(island.m_jointCount == island.m_jointCapacity) { + continue + } + if(jEdge.joint.m_islandFlag == true) { + continue + } + other = jEdge.other; + if(other.IsActive() == false) { + continue + } + island.AddJoint(jEdge.joint); + jEdge.joint.m_islandFlag = true; + if(other.m_flags & b2Body.e_islandFlag) { + continue + } + if(other.GetType() != b2Body.b2_staticBody) { + other.Advance(minTOI); + other.SetAwake(true) + } + queue[queueStart + queueSize] = other; + ++queueSize; + other.m_flags |= b2Body.e_islandFlag + } + } + var subStep = b2World.s_timestep; + subStep.warmStarting = false; + subStep.dt = (1 - minTOI) * step.dt; + subStep.inv_dt = 1 / subStep.dt; + subStep.dtRatio = 0; + subStep.velocityIterations = step.velocityIterations; + subStep.positionIterations = step.positionIterations; + island.SolveTOI(subStep); + var i = 0; + for(i = 0;i < island.m_bodyCount;++i) { + b = island.m_bodies[i]; + b.m_flags &= ~b2Body.e_islandFlag; + if(b.IsAwake() == false) { + continue + } + if(b.GetType() != b2Body.b2_dynamicBody) { + continue + } + b.SynchronizeFixtures(); + for(cEdge = b.m_contactList;cEdge;cEdge = cEdge.next) { + cEdge.contact.m_flags &= ~b2Contact.e_toiFlag + } + } + for(i = 0;i < island.m_contactCount;++i) { + c = island.m_contacts[i]; + c.m_flags &= ~(b2Contact.e_toiFlag | b2Contact.e_islandFlag) + } + for(i = 0;i < island.m_jointCount;++i) { + j = island.m_joints[i]; + j.m_islandFlag = false + } + this.m_contactManager.FindNewContacts() + } +}; +b2World.prototype.DrawJoint = function(joint) { + var b1 = joint.GetBodyA(); + var b2 = joint.GetBodyB(); + var xf1 = b1.m_xf; + var xf2 = b2.m_xf; + var x1 = xf1.position; + var x2 = xf2.position; + var p1 = joint.GetAnchorA(); + var p2 = joint.GetAnchorB(); + var color = b2World.s_jointColor; + switch(joint.m_type) { + case b2Joint.e_distanceJoint: + this.m_debugDraw.DrawSegment(p1, p2, color); + break; + case b2Joint.e_pulleyJoint: + var pulley = joint; + var s1 = pulley.GetGroundAnchorA(); + var s2 = pulley.GetGroundAnchorB(); + this.m_debugDraw.DrawSegment(s1, p1, color); + this.m_debugDraw.DrawSegment(s2, p2, color); + this.m_debugDraw.DrawSegment(s1, s2, color); + break; + case b2Joint.e_mouseJoint: + this.m_debugDraw.DrawSegment(p1, p2, color); + break; + default: + if(b1 != this.m_groundBody) { + this.m_debugDraw.DrawSegment(x1, p1, color) + } + this.m_debugDraw.DrawSegment(p1, p2, color); + if(b2 != this.m_groundBody) { + this.m_debugDraw.DrawSegment(x2, p2, color) + } + } +}; +b2World.prototype.DrawShape = function(shape, xf, color) { + switch(shape.m_type) { + case b2Shape.e_circleShape: + var circle = shape; + var center = b2Math.MulX(xf, circle.m_p); + var radius = circle.m_radius; + var axis = xf.R.col1; + this.m_debugDraw.DrawSolidCircle(center, radius, axis, color); + break; + case b2Shape.e_polygonShape: + var i = 0; + var poly = shape; + var vertexCount = poly.GetVertexCount(); + var localVertices = poly.GetVertices(); + var vertices = new Array(vertexCount); + for(i = 0;i < vertexCount;++i) { + vertices[i] = b2Math.MulX(xf, localVertices[i]) + } + this.m_debugDraw.DrawSolidPolygon(vertices, vertexCount, color); + break; + case b2Shape.e_edgeShape: + var edge = shape; + this.m_debugDraw.DrawSegment(b2Math.MulX(xf, edge.GetVertex1()), b2Math.MulX(xf, edge.GetVertex2()), color); + break + } +}; +b2World.prototype.SetDestructionListener = function(listener) { + this.m_destructionListener = listener +}; +b2World.prototype.SetContactFilter = function(filter) { + this.m_contactManager.m_contactFilter = filter +}; +b2World.prototype.SetContactListener = function(listener) { + this.m_contactManager.m_contactListener = listener +}; +b2World.prototype.SetDebugDraw = function(debugDraw) { + this.m_debugDraw = debugDraw +}; +b2World.prototype.SetBroadPhase = function(broadPhase) { + var oldBroadPhase = this.m_contactManager.m_broadPhase; + this.m_contactManager.m_broadPhase = broadPhase; + for(var b = this.m_bodyList;b;b = b.m_next) { + for(var f = b.m_fixtureList;f;f = f.m_next) { + f.m_proxy = broadPhase.CreateProxy(oldBroadPhase.GetFatAABB(f.m_proxy), f) + } + } +}; +b2World.prototype.Validate = function() { + this.m_contactManager.m_broadPhase.Validate() +}; +b2World.prototype.GetProxyCount = function() { + return this.m_contactManager.m_broadPhase.GetProxyCount() +}; +b2World.prototype.CreateBody = function(def) { + if(this.IsLocked() == true) { + return null + } + var b = new b2Body(def, this); + b.m_prev = null; + b.m_next = this.m_bodyList; + if(this.m_bodyList) { + this.m_bodyList.m_prev = b + } + this.m_bodyList = b; + ++this.m_bodyCount; + return b +}; +b2World.prototype.DestroyBody = function(b) { + if(this.IsLocked() == true) { + return + } + var jn = b.m_jointList; + while(jn) { + var jn0 = jn; + jn = jn.next; + if(this.m_destructionListener) { + this.m_destructionListener.SayGoodbyeJoint(jn0.joint) + } + this.DestroyJoint(jn0.joint) + } + var coe = b.m_controllerList; + while(coe) { + var coe0 = coe; + coe = coe.nextController; + coe0.controller.RemoveBody(b) + } + var ce = b.m_contactList; + while(ce) { + var ce0 = ce; + ce = ce.next; + this.m_contactManager.Destroy(ce0.contact) + } + b.m_contactList = null; + var f = b.m_fixtureList; + while(f) { + var f0 = f; + f = f.m_next; + if(this.m_destructionListener) { + this.m_destructionListener.SayGoodbyeFixture(f0) + } + f0.DestroyProxy(this.m_contactManager.m_broadPhase); + f0.Destroy() + } + b.m_fixtureList = null; + b.m_fixtureCount = 0; + if(b.m_prev) { + b.m_prev.m_next = b.m_next + } + if(b.m_next) { + b.m_next.m_prev = b.m_prev + } + if(b == this.m_bodyList) { + this.m_bodyList = b.m_next + } + --this.m_bodyCount +}; +b2World.prototype.CreateJoint = function(def) { + var j = b2Joint.Create(def, null); + j.m_prev = null; + j.m_next = this.m_jointList; + if(this.m_jointList) { + this.m_jointList.m_prev = j + } + this.m_jointList = j; + ++this.m_jointCount; + j.m_edgeA.joint = j; + j.m_edgeA.other = j.m_bodyB; + j.m_edgeA.prev = null; + j.m_edgeA.next = j.m_bodyA.m_jointList; + if(j.m_bodyA.m_jointList) { + j.m_bodyA.m_jointList.prev = j.m_edgeA + } + j.m_bodyA.m_jointList = j.m_edgeA; + j.m_edgeB.joint = j; + j.m_edgeB.other = j.m_bodyA; + j.m_edgeB.prev = null; + j.m_edgeB.next = j.m_bodyB.m_jointList; + if(j.m_bodyB.m_jointList) { + j.m_bodyB.m_jointList.prev = j.m_edgeB + } + j.m_bodyB.m_jointList = j.m_edgeB; + var bodyA = def.bodyA; + var bodyB = def.bodyB; + if(def.collideConnected == false) { + var edge = bodyB.GetContactList(); + while(edge) { + if(edge.other == bodyA) { + edge.contact.FlagForFiltering() + } + edge = edge.next + } + } + return j +}; +b2World.prototype.DestroyJoint = function(j) { + var collideConnected = j.m_collideConnected; + if(j.m_prev) { + j.m_prev.m_next = j.m_next + } + if(j.m_next) { + j.m_next.m_prev = j.m_prev + } + if(j == this.m_jointList) { + this.m_jointList = j.m_next + } + var bodyA = j.m_bodyA; + var bodyB = j.m_bodyB; + bodyA.SetAwake(true); + bodyB.SetAwake(true); + if(j.m_edgeA.prev) { + j.m_edgeA.prev.next = j.m_edgeA.next + } + if(j.m_edgeA.next) { + j.m_edgeA.next.prev = j.m_edgeA.prev + } + if(j.m_edgeA == bodyA.m_jointList) { + bodyA.m_jointList = j.m_edgeA.next + } + j.m_edgeA.prev = null; + j.m_edgeA.next = null; + if(j.m_edgeB.prev) { + j.m_edgeB.prev.next = j.m_edgeB.next + } + if(j.m_edgeB.next) { + j.m_edgeB.next.prev = j.m_edgeB.prev + } + if(j.m_edgeB == bodyB.m_jointList) { + bodyB.m_jointList = j.m_edgeB.next + } + j.m_edgeB.prev = null; + j.m_edgeB.next = null; + b2Joint.Destroy(j, null); + --this.m_jointCount; + if(collideConnected == false) { + var edge = bodyB.GetContactList(); + while(edge) { + if(edge.other == bodyA) { + edge.contact.FlagForFiltering() + } + edge = edge.next + } + } +}; +b2World.prototype.AddController = function(c) { + c.m_next = this.m_controllerList; + c.m_prev = null; + this.m_controllerList = c; + c.m_world = this; + this.m_controllerCount++; + return c +}; +b2World.prototype.RemoveController = function(c) { + if(c.m_prev) { + c.m_prev.m_next = c.m_next + } + if(c.m_next) { + c.m_next.m_prev = c.m_prev + } + if(this.m_controllerList == c) { + this.m_controllerList = c.m_next + } + this.m_controllerCount-- +}; +b2World.prototype.CreateController = function(controller) { + if(controller.m_world != this) { + throw new Error("Controller can only be a member of one world"); + } + controller.m_next = this.m_controllerList; + controller.m_prev = null; + if(this.m_controllerList) { + this.m_controllerList.m_prev = controller + } + this.m_controllerList = controller; + ++this.m_controllerCount; + controller.m_world = this; + return controller +}; +b2World.prototype.DestroyController = function(controller) { + controller.Clear(); + if(controller.m_next) { + controller.m_next.m_prev = controller.m_prev + } + if(controller.m_prev) { + controller.m_prev.m_next = controller.m_next + } + if(controller == this.m_controllerList) { + this.m_controllerList = controller.m_next + } + --this.m_controllerCount +}; +b2World.prototype.SetWarmStarting = function(flag) { + b2World.m_warmStarting = flag +}; +b2World.prototype.SetContinuousPhysics = function(flag) { + b2World.m_continuousPhysics = flag +}; +b2World.prototype.GetBodyCount = function() { + return this.m_bodyCount +}; +b2World.prototype.GetJointCount = function() { + return this.m_jointCount +}; +b2World.prototype.GetContactCount = function() { + return this.m_contactCount +}; +b2World.prototype.SetGravity = function(gravity) { + this.m_gravity = gravity +}; +b2World.prototype.GetGravity = function() { + return this.m_gravity +}; +b2World.prototype.GetGroundBody = function() { + return this.m_groundBody +}; +b2World.prototype.Step = function(dt, velocityIterations, positionIterations) { + if(this.m_flags & b2World.e_newFixture) { + this.m_contactManager.FindNewContacts(); + this.m_flags &= ~b2World.e_newFixture + } + this.m_flags |= b2World.e_locked; + var step = b2World.s_timestep2; + step.dt = dt; + step.velocityIterations = velocityIterations; + step.positionIterations = positionIterations; + if(dt > 0) { + step.inv_dt = 1 / dt + }else { + step.inv_dt = 0 + } + step.dtRatio = this.m_inv_dt0 * dt; + step.warmStarting = b2World.m_warmStarting; + this.m_contactManager.Collide(); + if(step.dt > 0) { + this.Solve(step) + } + if(b2World.m_continuousPhysics && step.dt > 0) { + this.SolveTOI(step) + } + if(step.dt > 0) { + this.m_inv_dt0 = step.inv_dt + } + this.m_flags &= ~b2World.e_locked +}; +b2World.prototype.ClearForces = function() { + for(var body = this.m_bodyList;body;body = body.m_next) { + body.m_force.SetZero(); + body.m_torque = 0 + } +}; +b2World.prototype.DrawDebugData = function() { + if(this.m_debugDraw == null) { + return + } + this.m_debugDraw.Clear(); + var flags = this.m_debugDraw.GetFlags(); + var i = 0; + var b; + var f; + var s; + var j; + var bp; + var invQ = new b2Vec2; + var x1 = new b2Vec2; + var x2 = new b2Vec2; + var xf; + var b1 = new b2AABB; + var b2 = new b2AABB; + var vs = [new b2Vec2, new b2Vec2, new b2Vec2, new b2Vec2]; + var color = new b2Color(0, 0, 0); + if(flags & b2DebugDraw.e_shapeBit) { + for(b = this.m_bodyList;b;b = b.m_next) { + xf = b.m_xf; + for(f = b.GetFixtureList();f;f = f.m_next) { + s = f.GetShape(); + if(b.IsActive() == false) { + color.Set(0.5, 0.5, 0.3); + this.DrawShape(s, xf, color) + }else { + if(b.GetType() == b2Body.b2_staticBody) { + color.Set(0.5, 0.9, 0.5); + this.DrawShape(s, xf, color) + }else { + if(b.GetType() == b2Body.b2_kinematicBody) { + color.Set(0.5, 0.5, 0.9); + this.DrawShape(s, xf, color) + }else { + if(b.IsAwake() == false) { + color.Set(0.6, 0.6, 0.6); + this.DrawShape(s, xf, color) + }else { + color.Set(0.9, 0.7, 0.7); + this.DrawShape(s, xf, color) + } + } + } + } + } + } + } + if(flags & b2DebugDraw.e_jointBit) { + for(j = this.m_jointList;j;j = j.m_next) { + this.DrawJoint(j) + } + } + if(flags & b2DebugDraw.e_controllerBit) { + for(var c = this.m_controllerList;c;c = c.m_next) { + c.Draw(this.m_debugDraw) + } + } + if(flags & b2DebugDraw.e_pairBit) { + color.Set(0.3, 0.9, 0.9); + for(var contact = this.m_contactManager.m_contactList;contact;contact = contact.GetNext()) { + var fixtureA = contact.GetFixtureA(); + var fixtureB = contact.GetFixtureB(); + var cA = fixtureA.GetAABB().GetCenter(); + var cB = fixtureB.GetAABB().GetCenter(); + this.m_debugDraw.DrawSegment(cA, cB, color) + } + } + if(flags & b2DebugDraw.e_aabbBit) { + bp = this.m_contactManager.m_broadPhase; + vs = [new b2Vec2, new b2Vec2, new b2Vec2, new b2Vec2]; + for(b = this.m_bodyList;b;b = b.GetNext()) { + if(b.IsActive() == false) { + continue + } + for(f = b.GetFixtureList();f;f = f.GetNext()) { + var aabb = bp.GetFatAABB(f.m_proxy); + vs[0].Set(aabb.lowerBound.x, aabb.lowerBound.y); + vs[1].Set(aabb.upperBound.x, aabb.lowerBound.y); + vs[2].Set(aabb.upperBound.x, aabb.upperBound.y); + vs[3].Set(aabb.lowerBound.x, aabb.upperBound.y); + this.m_debugDraw.DrawPolygon(vs, 4, color) + } + } + } + if(flags & b2DebugDraw.e_centerOfMassBit) { + for(b = this.m_bodyList;b;b = b.m_next) { + xf = b2World.s_xf; + xf.R = b.m_xf.R; + xf.position = b.GetWorldCenter(); + this.m_debugDraw.DrawTransform(xf) + } + } +}; +b2World.prototype.QueryAABB = function(callback, aabb) { + var broadPhase = this.m_contactManager.m_broadPhase; + function WorldQueryWrapper(proxy) { + return callback(broadPhase.GetUserData(proxy)) + } + broadPhase.Query(WorldQueryWrapper, aabb) +}; +b2World.prototype.QueryShape = function(callback, shape, transform) { + if(transform == null) { + transform = new b2Transform; + transform.SetIdentity() + } + var broadPhase = this.m_contactManager.m_broadPhase; + function WorldQueryWrapper(proxy) { + var fixture = broadPhase.GetUserData(proxy); + if(b2Shape.TestOverlap(shape, transform, fixture.GetShape(), fixture.GetBody().GetTransform())) { + return callback(fixture) + } + return true + } + var aabb = new b2AABB; + shape.ComputeAABB(aabb, transform); + broadPhase.Query(WorldQueryWrapper, aabb) +}; +b2World.prototype.QueryPoint = function(callback, p) { + var broadPhase = this.m_contactManager.m_broadPhase; + function WorldQueryWrapper(proxy) { + var fixture = broadPhase.GetUserData(proxy); + if(fixture.TestPoint(p)) { + return callback(fixture) + } + return true + } + var aabb = new b2AABB; + aabb.lowerBound.Set(p.x - b2Settings.b2_linearSlop, p.y - b2Settings.b2_linearSlop); + aabb.upperBound.Set(p.x + b2Settings.b2_linearSlop, p.y + b2Settings.b2_linearSlop); + broadPhase.Query(WorldQueryWrapper, aabb) +}; +b2World.prototype.RayCast = function(callback, point1, point2) { + var broadPhase = this.m_contactManager.m_broadPhase; + var output = new b2RayCastOutput; + function RayCastWrapper(input, proxy) { + var userData = broadPhase.GetUserData(proxy); + var fixture = userData; + var hit = fixture.RayCast(output, input); + if(hit) { + var fraction = output.fraction; + var point = new b2Vec2((1 - fraction) * point1.x + fraction * point2.x, (1 - fraction) * point1.y + fraction * point2.y); + return callback(fixture, point, output.normal, fraction) + } + return input.maxFraction + } + var input = new b2RayCastInput(point1, point2); + broadPhase.RayCast(RayCastWrapper, input) +}; +b2World.prototype.RayCastOne = function(point1, point2) { + var result; + function RayCastOneWrapper(fixture, point, normal, fraction) { + result = fixture; + return fraction + } + this.RayCast(RayCastOneWrapper, point1, point2); + return result +}; +b2World.prototype.RayCastAll = function(point1, point2) { + var result = new Array; + function RayCastAllWrapper(fixture, point, normal, fraction) { + result[result.length] = fixture; + return 1 + } + this.RayCast(RayCastAllWrapper, point1, point2); + return result +}; +b2World.prototype.GetBodyList = function() { + return this.m_bodyList +}; +b2World.prototype.GetJointList = function() { + return this.m_jointList +}; +b2World.prototype.GetContactList = function() { + return this.m_contactList +}; +b2World.prototype.IsLocked = function() { + return(this.m_flags & b2World.e_locked) > 0 +}; +b2World.prototype.s_stack = new Array; +b2World.prototype.m_flags = 0; +b2World.prototype.m_contactManager = new b2ContactManager; +b2World.prototype.m_contactSolver = new b2ContactSolver; +b2World.prototype.m_island = new b2Island; +b2World.prototype.m_bodyList = null; +b2World.prototype.m_jointList = null; +b2World.prototype.m_contactList = null; +b2World.prototype.m_bodyCount = 0; +b2World.prototype.m_contactCount = 0; +b2World.prototype.m_jointCount = 0; +b2World.prototype.m_controllerList = null; +b2World.prototype.m_controllerCount = 0; +b2World.prototype.m_gravity = null; +b2World.prototype.m_allowSleep = null; +b2World.prototype.m_groundBody = null; +b2World.prototype.m_destructionListener = null; +b2World.prototype.m_debugDraw = null; +b2World.prototype.m_inv_dt0 = null;if(typeof exports !== "undefined") { + exports.b2BoundValues = b2BoundValues; + exports.b2Math = b2Math; + exports.b2DistanceOutput = b2DistanceOutput; + exports.b2Mat33 = b2Mat33; + exports.b2ContactPoint = b2ContactPoint; + exports.b2PairManager = b2PairManager; + exports.b2PositionSolverManifold = b2PositionSolverManifold; + exports.b2OBB = b2OBB; + exports.b2CircleContact = b2CircleContact; + exports.b2PulleyJoint = b2PulleyJoint; + exports.b2Pair = b2Pair; + exports.b2TimeStep = b2TimeStep; + exports.b2FixtureDef = b2FixtureDef; + exports.b2World = b2World; + exports.b2PrismaticJoint = b2PrismaticJoint; + exports.b2Controller = b2Controller; + exports.b2ContactID = b2ContactID; + exports.b2RevoluteJoint = b2RevoluteJoint; + exports.b2JointDef = b2JointDef; + exports.b2Transform = b2Transform; + exports.b2GravityController = b2GravityController; + exports.b2EdgeAndCircleContact = b2EdgeAndCircleContact; + exports.b2EdgeShape = b2EdgeShape; + exports.b2BuoyancyController = b2BuoyancyController; + exports.b2LineJointDef = b2LineJointDef; + exports.b2Contact = b2Contact; + exports.b2DistanceJoint = b2DistanceJoint; + exports.b2Body = b2Body; + exports.b2DestructionListener = b2DestructionListener; + exports.b2PulleyJointDef = b2PulleyJointDef; + exports.b2ContactEdge = b2ContactEdge; + exports.b2ContactConstraint = b2ContactConstraint; + exports.b2ContactImpulse = b2ContactImpulse; + exports.b2DistanceJointDef = b2DistanceJointDef; + exports.b2ContactResult = b2ContactResult; + exports.b2EdgeChainDef = b2EdgeChainDef; + exports.b2Vec2 = b2Vec2; + exports.b2Vec3 = b2Vec3; + exports.b2DistanceProxy = b2DistanceProxy; + exports.b2FrictionJointDef = b2FrictionJointDef; + exports.b2PolygonContact = b2PolygonContact; + exports.b2TensorDampingController = b2TensorDampingController; + exports.b2ContactFactory = b2ContactFactory; + exports.b2WeldJointDef = b2WeldJointDef; + exports.b2ConstantAccelController = b2ConstantAccelController; + exports.b2GearJointDef = b2GearJointDef; + exports.ClipVertex = ClipVertex; + exports.b2SeparationFunction = b2SeparationFunction; + exports.b2ManifoldPoint = b2ManifoldPoint; + exports.b2Color = b2Color; + exports.b2PolygonShape = b2PolygonShape; + exports.b2DynamicTreePair = b2DynamicTreePair; + exports.b2ContactConstraintPoint = b2ContactConstraintPoint; + exports.b2FrictionJoint = b2FrictionJoint; + exports.b2ContactFilter = b2ContactFilter; + exports.b2ControllerEdge = b2ControllerEdge; + exports.b2Distance = b2Distance; + exports.b2Fixture = b2Fixture; + exports.b2DynamicTreeNode = b2DynamicTreeNode; + exports.b2MouseJoint = b2MouseJoint; + exports.b2DistanceInput = b2DistanceInput; + exports.b2BodyDef = b2BodyDef; + exports.b2DynamicTreeBroadPhase = b2DynamicTreeBroadPhase; + exports.b2Settings = b2Settings; + exports.b2Proxy = b2Proxy; + exports.b2Point = b2Point; + exports.b2BroadPhase = b2BroadPhase; + exports.b2Manifold = b2Manifold; + exports.b2WorldManifold = b2WorldManifold; + exports.b2PrismaticJointDef = b2PrismaticJointDef; + exports.b2RayCastOutput = b2RayCastOutput; + exports.b2ConstantForceController = b2ConstantForceController; + exports.b2TimeOfImpact = b2TimeOfImpact; + exports.b2CircleShape = b2CircleShape; + exports.b2MassData = b2MassData; + exports.b2Joint = b2Joint; + exports.b2GearJoint = b2GearJoint; + exports.b2DynamicTree = b2DynamicTree; + exports.b2JointEdge = b2JointEdge; + exports.b2LineJoint = b2LineJoint; + exports.b2NullContact = b2NullContact; + exports.b2ContactListener = b2ContactListener; + exports.b2RayCastInput = b2RayCastInput; + exports.b2TOIInput = b2TOIInput; + exports.Features = Features; + exports.b2FilterData = b2FilterData; + exports.b2Island = b2Island; + exports.b2ContactManager = b2ContactManager; + exports.b2ContactSolver = b2ContactSolver; + exports.b2Simplex = b2Simplex; + exports.b2AABB = b2AABB; + exports.b2Jacobian = b2Jacobian; + exports.b2Bound = b2Bound; + exports.b2RevoluteJointDef = b2RevoluteJointDef; + exports.b2PolyAndEdgeContact = b2PolyAndEdgeContact; + exports.b2SimplexVertex = b2SimplexVertex; + exports.b2WeldJoint = b2WeldJoint; + exports.b2Collision = b2Collision; + exports.b2Mat22 = b2Mat22; + exports.b2SimplexCache = b2SimplexCache; + exports.b2PolyAndCircleContact = b2PolyAndCircleContact; + exports.b2MouseJointDef = b2MouseJointDef; + exports.b2Shape = b2Shape; + exports.b2Segment = b2Segment; + exports.b2ContactRegister = b2ContactRegister; + exports.b2DebugDraw = b2DebugDraw; + exports.b2Sweep = b2Sweep +} +; diff --git a/src/libs/cocos2d/ActionManager.js b/src/libs/cocos2d/ActionManager.js index e30cb7b..21a71e5 100644 --- a/src/libs/cocos2d/ActionManager.js +++ b/src/libs/cocos2d/ActionManager.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), console = require('system').console, Timer = require('./Scheduler').Timer, @@ -24,8 +28,8 @@ var ActionManager = BObject.extend(/** @lends cocos.ActionManager# */{ * @extends BObject * @singleton */ - init: function() { - @super; + init: function () { + ActionManager.superclass.init.call(this); Scheduler.get('sharedScheduler').scheduleUpdate({target: this, priority: 0, paused: false}); this.targets = []; @@ -40,22 +44,22 @@ var ActionManager = BObject.extend(/** @lends cocos.ActionManager# */{ * * @opt {cocos.nodes.Node} target Node to run the action on */ - addAction: function(opts) { + addAction: function (opts) { - var targetID = opts['target'].get('id'); + var targetID = opts.target.get('id'); var element = this.targets[targetID]; if (!element) { element = this.targets[targetID] = { paused: false, - target: opts['target'], + target: opts.target, actions: [] }; } - element.actions.push(opts['action']); + element.actions.push(opts.action); - opts['action'].startWithTarget(opts['target']); + opts.action.startWithTarget(opts.target); }, /** @@ -63,7 +67,7 @@ var ActionManager = BObject.extend(/** @lends cocos.ActionManager# */{ * * @param {cocos.actions.Action} action Action to remove */ - removeAction: function(action) { + removeAction: function (action) { var targetID = action.originalTarget.get('id'), element = this.targets[targetID]; @@ -84,7 +88,7 @@ var ActionManager = BObject.extend(/** @lends cocos.ActionManager# */{ element.actions[actionIndex] = null; element.actions.splice(actionIndex, 1); // Delete array item - if (element.actions.length == 0) { + if (element.actions.length === 0) { if (this.currentTarget == element) { this.set('currentTargetSalvaged', true); } @@ -92,36 +96,65 @@ var ActionManager = BObject.extend(/** @lends cocos.ActionManager# */{ }, + /** + * Fetch an action belonging to a cocos.nodes.Node + * + * @returns {cocos.actions.Action} + * + * @opts {cocos.nodes.Node} target Target of the action + * @opts {String} tag Tag of the action + */ + getActionFromTarget: function(opts) { + var tag = opts.tag, + targetID = opts.target.get('id'); + + var element = this.targets[targetID]; + if (!element) { + return null; + } + for (var i = 0; i < element.actions.length; i++ ) { + if (element.actions[i] && + (element.actions[i].get('tag') === tag)) { + return element.actions[i]; + } + } + // Not found + return null; + }, + /** * Remove all actions for a cocos.nodes.Node * * @param {cocos.nodes.Node} target Node to remove all actions for */ - removeAllActionsFromTarget: function(target) { + removeAllActionsFromTarget: function (target) { var targetID = target.get('id'); var element = this.targets[targetID]; if (!element) { return; } - // Delete everything in array but don't replace it incase something else has a reference - element.actions.splice(0, element.actions.length-1); + element.actions.splice(0, element.actions.length); }, /** * @private */ - update: function(dt) { + update: function (dt) { var self = this; - util.each(this.targets, function(currentTarget, i) { + util.each(this.targets, function (currentTarget, i) { - if (!currentTarget) return; + if (!currentTarget) { + return; + } self.currentTarget = currentTarget; if (!currentTarget.paused) { - util.each(currentTarget.actions, function(currentAction, j) { - if (!currentAction) return; + util.each(currentTarget.actions, function (currentAction, j) { + if (!currentAction) { + return; + } currentTarget.currentAction = currentAction; currentTarget.currentActionSalvaged = false; @@ -141,21 +174,19 @@ var ActionManager = BObject.extend(/** @lends cocos.ActionManager# */{ }); } - if (self.currentTargetSalvaged && currentTarget.actions.length == 0) { + if (self.currentTargetSalvaged && currentTarget.actions.length === 0) { self.targets[i] = null; delete self.targets[i]; } }); - - delete self; }, - pauseTarget: function(target) { + pauseTarget: function (target) { }, - resumeTarget: function(target) { - // TODO - } + resumeTarget: function (target) { + // TODO + } }); util.extend(ActionManager, /** @lends cocos.ActionManager */{ @@ -164,7 +195,7 @@ util.extend(ActionManager, /** @lends cocos.ActionManager */{ * @getter sharedManager * @type cocos.ActionManager */ - get_sharedManager: function(key) { + get_sharedManager: function (key) { if (!this._instance) { this._instance = this.create(); } diff --git a/src/libs/cocos2d/Animation.js b/src/libs/cocos2d/Animation.js index 92a0f6e..822c124 100644 --- a/src/libs/cocos2d/Animation.js +++ b/src/libs/cocos2d/Animation.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'); var Animation = BObject.extend(/** @lends cocos.Animation# */{ @@ -22,11 +26,11 @@ var Animation = BObject.extend(/** @lends cocos.Animation# */{ * var animation = cocos.Animation.create({frames: [f1, f2, f3], delay: 0.1}); * sprite.runAction(cocos.actions.Animate.create({animation: animation})); */ - init: function(opts) { - @super; + init: function (opts) { + Animation.superclass.init.call(this, opts); - this.frames = opts['frames'] || []; - this.delay = opts['delay'] || 0.0; + this.frames = opts.frames || []; + this.delay = opts.delay || 0.0; } }); diff --git a/src/libs/cocos2d/AnimationCache.js b/src/libs/cocos2d/AnimationCache.js index 5d6259d..faeeaee 100644 --- a/src/libs/cocos2d/AnimationCache.js +++ b/src/libs/cocos2d/AnimationCache.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), Plist = require('Plist').Plist; @@ -14,8 +18,8 @@ var AnimationCache = BObject.extend(/** @lends cocos.AnimationCache# */{ * @extends BObject * @singleton */ - init: function() { - @super; + init: function () { + AnimationCache.superclass.init.call(this); this.set('animations', {}); }, @@ -26,9 +30,9 @@ var AnimationCache = BObject.extend(/** @lends cocos.AnimationCache# */{ * @opt {String} name Unique name of the animation * @opt {cocos.Animcation} animation Animation to cache */ - addAnimation: function(opts) { - var name = opts['name'], - animation = opts['animation']; + addAnimation: function (opts) { + var name = opts.name, + animation = opts.animation; this.get('animations')[name] = animation; }, @@ -38,8 +42,8 @@ var AnimationCache = BObject.extend(/** @lends cocos.AnimationCache# */{ * * @opt {String} name Unique name of the animation */ - removeAnimation: function(opts) { - var name = opts['name']; + removeAnimation: function (opts) { + var name = opts.name; delete this.get('animations')[name]; }, @@ -50,8 +54,8 @@ var AnimationCache = BObject.extend(/** @lends cocos.AnimationCache# */{ * @opt {String} name Unique name of the animation * @returns {cocos.Animation} Cached animation */ - getAnimation: function(opts) { - var name = opts['name']; + getAnimation: function (opts) { + var name = opts.name; return this.get('animations')[name]; } @@ -65,7 +69,7 @@ util.extend(AnimationCache, /** @lends cocos.AnimationCache */{ * @getter sharedAnimationCache * @type cocos.AnimationCache */ - get_sharedAnimationCache: function(key) { + get_sharedAnimationCache: function (key) { if (!this._instance) { this._instance = this.create(); } diff --git a/src/libs/cocos2d/Director.js b/src/libs/cocos2d/Director.js index c109a36..b8a716f 100644 --- a/src/libs/cocos2d/Director.js +++ b/src/libs/cocos2d/Director.js @@ -1,10 +1,32 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS SHOW_REDRAW_REGIONS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), geo = require('geometry'), ccp = geo.ccp, + events = require('events'), Scheduler = require('./Scheduler').Scheduler, EventDispatcher = require('./EventDispatcher').EventDispatcher, Scene = require('./nodes/Scene').Scene; + +/** + * requestAnimationFrame for smart animating + * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + */ + +window.requestAnimFrame = (function (){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + window.setTimeout(callback, 1000 / 30); + }; +})(); + var Director = BObject.extend(/** @lends cocos.Director# */{ backgroundColor: 'rgb(0, 0, 0)', canvas: null, @@ -14,13 +36,15 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ isPaused: false, maxFrameRate: 30, displayFPS: false, + preloadScene: null, + isReady: false, // Time delta dt: 0, nextDeltaTimeZero: false, lastUpdate: 0, - _nextScene:null, + _nextScene: null, /** *

Creates and handles the main view and manages how and when to execute the @@ -34,8 +58,8 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * @extends BObject * @singleton */ - init: function() { - @super; + init: function () { + Director.superclass.init.call(this); this.set('sceneStack', []); }, @@ -45,86 +69,167 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * * @param {HTMLElement} view Any HTML element to add the application to */ - attachInView: function(view) { - if (!view.tagName) { - throw "Director.attachInView must be given a HTML DOM Node"; - } - - while (view.firstChild) { - view.removeChild(view.firstChild); - } - - var canvas = document.createElement('canvas'); - this.set('canvas', canvas); - canvas.setAttribute('width', view.clientWidth); - canvas.setAttribute('height', view.clientHeight); - var context = canvas.getContext('2d'); - this.set('context', context); + attachInView: function (view) { + if (!view.tagName) { + throw "Director.attachInView must be given a HTML DOM Node"; + } + + while (view.firstChild) { + view.removeChild(view.firstChild); + } + + var canvas = document.createElement('canvas'); + this.set('canvas', canvas); + canvas.setAttribute('width', view.clientWidth); + canvas.setAttribute('height', view.clientHeight); + + var context = canvas.getContext('2d'); + this.set('context', context); + + if (FLIP_Y_AXIS) { + context.translate(0, view.clientHeight); + context.scale(1, -1); + } - view.appendChild(canvas); - - this.set('winSize', {width: view.clientWidth, height: view.clientHeight}); - - - // Setup event handling - - // Mouse events - var eventDispatcher = EventDispatcher.get('sharedDispatcher'); - var self = this; - function mouseDown(evt) { - evt.locationInWindow = ccp(evt.clientX, evt.clientY); - evt.locationInCanvas = self.convertEventToCanvas(evt); - - function mouseDragged(evt) { - evt.locationInWindow = ccp(evt.clientX, evt.clientY); - evt.locationInCanvas = self.convertEventToCanvas(evt); - - eventDispatcher.mouseDragged(evt); - }; - function mouseUp(evt) { - evt.locationInWindow = ccp(evt.clientX, evt.clientY); - evt.locationInCanvas = self.convertEventToCanvas(evt); - - document.body.removeEventListener('mousemove', mouseDragged, false); - document.body.removeEventListener('mouseup', mouseUp, false); - - - eventDispatcher.mouseUp(evt); - }; + view.appendChild(canvas); + + this.set('winSize', {width: view.clientWidth, height: view.clientHeight}); - document.body.addEventListener('mousemove', mouseDragged, false); - document.body.addEventListener('mouseup', mouseUp, false); + // Setup event handling - eventDispatcher.mouseDown(evt); + // Mouse events + var eventDispatcher = EventDispatcher.get('sharedDispatcher'); + var self = this; + function mouseDown(evt) { + evt.locationInWindow = ccp(evt.clientX, evt.clientY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + + function mouseDragged(evt) { + evt.locationInWindow = ccp(evt.clientX, evt.clientY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + + eventDispatcher.mouseDragged(evt); + } + function mouseUp(evt) { + evt.locationInWindow = ccp(evt.clientX, evt.clientY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + + document.body.removeEventListener('mousemove', mouseDragged, false); + document.body.removeEventListener('mouseup', mouseUp, false); + + eventDispatcher.mouseUp(evt); + } + + document.body.addEventListener('mousemove', mouseDragged, false); + document.body.addEventListener('mouseup', mouseUp, false); + + eventDispatcher.mouseDown(evt); + } + function mouseMoved(evt) { + evt.locationInWindow = ccp(evt.clientX, evt.clientY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + + eventDispatcher.mouseMoved(evt); + } + + canvas.addEventListener('mousedown', mouseDown, false); + canvas.addEventListener('mousemove', mouseMoved, false); + + // Add handlers for touch events. + + // for touchcancel event - can be fired anytime so must be defined outside + // touchStart() + function touchEnd(evt) { + if (!evt) evt = event; + evt.preventDefault(); + + // evt.changedTouches should have the last touch point + if (evt.changedTouches.length == 1) { + evt.locationInWindow = ccp(evt.changedTouches[0].pageX, evt.changedTouches[0].pageY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + } + eventDispatcher.mouseUp(evt); + } + + function touchStart(evt) { + if (!evt) evt = event; + + if (evt.touches.length == 1) { + evt.locationInWindow = ccp(evt.touches[0].pageX, evt.touches[0].pageY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + } else { + // TODO: multitouch support?? + } + + function touchMoved(evt) { + if (!evt) evt = event; + evt.preventDefault(); + + if (evt.touches.length == 1) { + evt.locationInWindow = ccp(evt.touches[0].pageX, evt.touches[0].pageY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + + eventDispatcher.mouseDragged(evt); + } else { + // TODO: multitouch support?? + } + } + + function touchUp(evt) { + if (!evt) evt = event; + evt.preventDefault(); + + // evt.changedTouches should have the last touch point + if (evt.changedTouches.length == 1) { + evt.locationInWindow = ccp(evt.changedTouches[0].pageX, evt.changedTouches[0].pageY); + evt.locationInCanvas = self.convertEventToCanvas(evt); + + canvas.removeEventListener('touchmove', touchMoved, false); + canvas.removeEventListener('touchend', touchUp, false); + + eventDispatcher.mouseUp(evt); + } + } + + canvas.addEventListener('touchmove', touchMoved, false); + canvas.addEventListener('touchend', touchUp, false); + + eventDispatcher.mouseDown(evt); + } + + canvas.addEventListener('touchstart', touchStart, false); + // touchcancel must be bound to the body + document.body.addEventListener('touchcancel', touchEnd, false); + + // Keyboard events + function keyDown(evt) { + this._keysDown = this._keysDown || {}; + eventDispatcher.keyDown(evt); + } + function keyUp(evt) { + eventDispatcher.keyUp(evt); + } + + document.documentElement.addEventListener('keydown', keyDown, false); + document.documentElement.addEventListener('keyup', keyUp, false); + }, + + runPreloadScene: function () { + var preloader = this.get('preloadScene'); + if (!preloader) { + var PreloadScene = require('./nodes/PreloadScene').PreloadScene; + preloader = PreloadScene.create(); + this.set('preloadScene', preloader); } - function mouseMoved(evt) { - evt.locationInWindow = ccp(evt.clientX, evt.clientY); - evt.locationInCanvas = self.convertEventToCanvas(evt); - eventDispatcher.mouseMoved(evt); - } - canvas.addEventListener('mousedown', mouseDown, false); - canvas.addEventListener('mousemove', mouseMoved, false); + events.addListener(preloader, 'complete', util.callback(this, function (preloader) { + this.isReady = true; + events.trigger(this, 'ready', this); + })); - // Keyboard events - function keyDown(evt) { - this._keysDown = this._keysDown || {}; - eventDispatcher.keyDown(evt) - } - function keyUp(evt) { - eventDispatcher.keyUp(evt) - } - /* - function keyPress(evt) { - eventDispatcher.keyPress(evt) - } - */ - document.documentElement.addEventListener('keydown', keyDown, false); - document.documentElement.addEventListener('keyup', keyUp, false); - /* - document.documentElement.addEventListener('keypress', keyPress, false); - */ + this.pushScene(preloader); + this.startAnimation(); }, /** @@ -134,13 +239,13 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * * @param {cocos.Scene} scene The scene to start */ - runWithScene: function(scene) { + runWithScene: function (scene) { if (!(scene instanceof Scene)) { throw "Director.runWithScene must be given an instance of Scene"; } if (this._runningScene) { - throw "You can't run an scene if another Scene is running. Use replaceScene or pushScene instead" + throw "You can't run a Scene if another Scene is already running. Use replaceScene or pushScene instead"; } this.pushScene(scene); @@ -153,7 +258,7 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * * @param {cocos.Scene} scene The scene to replace with */ - replaceScene: function(scene) { + replaceScene: function (scene) { var index = this.sceneStack.length; this._sendCleanupToScene = true; @@ -168,7 +273,7 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * the stack the execution is terminated. ONLY call it if there is a * running scene. */ - popScene: function() { + popScene: function () { }, /** @@ -179,7 +284,7 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * * @param {cocos.Scene} scene The scene to add to the stack */ - pushScene: function(scene) { + pushScene: function (scene) { this._nextScene = scene; }, @@ -187,9 +292,14 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * The main loop is triggered again. Call this function only if * cocos.Directory#stopAnimation was called earlier. */ - startAnimation: function() { - var animationInterval = 1.0 / this.get('maxFrameRate'); - this._animationTimer = setInterval(util.callback(this, 'drawScene'), animationInterval * 1000); + startAnimation: function () { + this.animate(); + + }, + + animate: function() { + this.drawScene(); + window.requestAnimFrame(util.callback(this, 'animate'), this.canvas); }, /** @@ -197,15 +307,19 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * triggered anymore. If you want to pause your animation call * cocos.Directory#pause instead. */ - stopAnimation: function() { + stopAnimation: function () { + if (this._animationTimer) { + clearInterval(this._animationTimer); + this._animationTimer = null; + } }, /** * Calculate time since last call * @private */ - calculateDeltaTime: function() { - var now = (new Date).getTime() /1000; + calculateDeltaTime: function () { + var now = (new Date()).getTime() / 1000; if (this.nextDeltaTimeZero) { this.dt = 0; @@ -221,9 +335,9 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * The main run loop * @private */ - drawScene: function() { + drawScene: function () { this.calculateDeltaTime(); - + if (!this.isPaused) { Scheduler.get('sharedScheduler').tick(this.dt); } @@ -239,7 +353,26 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ this.setNextScene(); } - this._runningScene.visit(context); + var rect = new geo.Rect(0, 0, this.winSize.width, this.winSize.height); + + if (rect) { + context.beginPath(); + context.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + context.clip(); + context.closePath(); + } + + this._runningScene.visit(context, rect); + + if (SHOW_REDRAW_REGIONS) { + if (rect) { + context.beginPath(); + context.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + context.fillStyle = "rgba(255, 0, 0, 0.5)"; + //context.fill(); + context.closePath(); + } + } if (this.get('displayFPS')) { this.showFPS(); @@ -250,7 +383,7 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ * Initialises the next scene * @private */ - setNextScene: function() { + setNextScene: function () { // TODO transitions if (this._runningScene) { @@ -267,20 +400,25 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ this._runningScene.onEnter(); }, - convertEventToCanvas: function(evt) { + convertEventToCanvas: function (evt) { var x = this.canvas.offsetLeft - document.documentElement.scrollLeft, y = this.canvas.offsetTop - document.documentElement.scrollTop; var o = this.canvas; - while (o = o.offsetParent) { + while ((o = o.offsetParent)) { x += o.offsetLeft - o.scrollLeft; y += o.offsetTop - o.scrollTop; } - return geo.ccpSub(evt.locationInWindow, ccp(x, y)); + var p = geo.ccpSub(evt.locationInWindow, ccp(x, y)); + if (FLIP_Y_AXIS) { + p.y = this.canvas.height - p.y; + } + + return p; }, - showFPS: function() { + showFPS: function () { if (!this._fpsLabel) { var Label = require('./nodes/Label').Label; this._fpsLabel = Label.create({string: '', fontSize: 16}); @@ -293,14 +431,14 @@ var Director = BObject.extend(/** @lends cocos.Director# */{ this._frames++; this._accumDt += this.get('dt'); - if (this._accumDt > 1.0/3.0) { + if (this._accumDt > 1.0 / 3.0) { var frameRate = this._frames / this._accumDt; this._frames = 0; this._accumDt = 0; - this._fpsLabel.set('string', 'FPS: ' + (Math.round(frameRate*100)/100).toString()); + this._fpsLabel.set('string', 'FPS: ' + (Math.round(frameRate * 100) / 100).toString()); } - + var s = this.get('winSize'); this._fpsLabel.set('position', ccp(10, s.height - 10)); @@ -320,7 +458,7 @@ util.extend(Director, /** @lends cocos.Director */{ * @getter sharedDirector * @type cocos.Director */ - get_sharedDirector: function(key) { + get_sharedDirector: function (key) { if (!this._instance) { this._instance = this.create(); } diff --git a/src/libs/cocos2d/EventDispatcher.js b/src/libs/cocos2d/EventDispatcher.js index 10b7744..8ebd568 100644 --- a/src/libs/cocos2d/EventDispatcher.js +++ b/src/libs/cocos2d/EventDispatcher.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), geo = require('geometry'); @@ -15,8 +19,8 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ * @extends BObject * @singleton */ - init: function() { - @super; + init: function () { + EventDispatcher.superclass.init.call(this); this.keyboardDelegates = []; this.mouseDelegates = []; @@ -24,11 +28,11 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ this._keysDown = {}; }, - addDelegate: function(opts) { - var delegate = opts['delegate'], - priority = opts['priority'], - flags = opts['flags'], - list = opts['list']; + addDelegate: function (opts) { + var delegate = opts.delegate, + priority = opts.priority, + flags = opts.flags, + list = opts.list; var listElement = { delegate: delegate, @@ -53,9 +57,9 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ } }, - removeDelegate: function(opts) { - var delegate = opts['delegate'], - list = opts['list']; + removeDelegate: function (opts) { + var delegate = opts.delegate, + list = opts.list; var idx = -1, i; @@ -71,15 +75,15 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ } list.splice(idx, 1); }, - removeAllDelegates: function(opts) { - var list = opts['list']; + removeAllDelegates: function (opts) { + var list = opts.list; - list.splice(0, list.length -1); + list.splice(0, list.length - 1); }, - addMouseDelegate: function(opts) { - var delegate = opts['delegate'], - priority = opts['priority']; + addMouseDelegate: function (opts) { + var delegate = opts.delegate, + priority = opts.priority; var flags = 0; @@ -88,19 +92,19 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ this.addDelegate({delegate: delegate, priority: priority, flags: flags, list: this.mouseDelegates}); }, - removeMouseDelegate: function(opts) { - var delegate = opts['delegate']; + removeMouseDelegate: function (opts) { + var delegate = opts.delegate; this.removeDelegate({delegate: delegate, list: this.mouseDelegates}); }, - removeAllMouseDelegate: function() { + removeAllMouseDelegate: function () { this.removeAllDelegates({list: this.mouseDelegates}); }, - addKeyboardDelegate: function(opts) { - var delegate = opts['delegate'], - priority = opts['priority']; + addKeyboardDelegate: function (opts) { + var delegate = opts.delegate, + priority = opts.priority; var flags = 0; @@ -109,13 +113,13 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ this.addDelegate({delegate: delegate, priority: priority, flags: flags, list: this.keyboardDelegates}); }, - removeKeyboardDelegate: function(opts) { - var delegate = opts['delegate']; + removeKeyboardDelegate: function (opts) { + var delegate = opts.delegate; this.removeDelegate({delegate: delegate, list: this.keyboardDelegates}); }, - removeAllKeyboardDelegate: function() { + removeAllKeyboardDelegate: function () { this.removeAllDelegates({list: this.keyboardDelegates}); }, @@ -123,7 +127,7 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ // Mouse Events - mouseDown: function(evt) { + mouseDown: function (evt) { if (!this.dispatchEvents) { return; } @@ -141,7 +145,7 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ } } }, - mouseMoved: function(evt) { + mouseMoved: function (evt) { if (!this.dispatchEvents) { return; } @@ -149,6 +153,9 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ if (this._previousMouseMovePosition) { evt.deltaX = evt.clientX - this._previousMouseMovePosition.x; evt.deltaY = evt.clientY - this._previousMouseMovePosition.y; + if (FLIP_Y_AXIS) { + evt.deltaY *= -1; + } } else { evt.deltaX = 0; evt.deltaY = 0; @@ -165,7 +172,7 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ } } }, - mouseDragged: function(evt) { + mouseDragged: function (evt) { if (!this.dispatchEvents) { return; } @@ -173,6 +180,9 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ if (this._previousMouseDragPosition) { evt.deltaX = evt.clientX - this._previousMouseDragPosition.x; evt.deltaY = evt.clientY - this._previousMouseDragPosition.y; + if (FLIP_Y_AXIS) { + evt.deltaY *= -1; + } } else { evt.deltaX = 0; evt.deltaY = 0; @@ -187,9 +197,9 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ break; } } - }; + } }, - mouseUp: function(evt) { + mouseUp: function (evt) { if (!this.dispatchEvents) { return; } @@ -206,7 +216,7 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ }, // Keyboard events - keyDown: function(evt) { + keyDown: function (evt) { var kc = evt.keyCode; if (!this.dispatchEvents || this._keysDown[kc]) { return; @@ -225,7 +235,7 @@ var EventDispatcher = BObject.extend(/** @lends cocos.EventDispatcher# */{ } }, - keyUp: function(evt) { + keyUp: function (evt) { if (!this.dispatchEvents) { return; } @@ -258,7 +268,7 @@ util.extend(EventDispatcher, /** @lends cocos.EventDispatcher */{ * @getter sharedDispatcher * @type cocos.EventDispatcher */ - get_sharedDispatcher: function(key) { + get_sharedDispatcher: function (key) { if (!this._instance) { this._instance = this.create(); } diff --git a/src/libs/cocos2d/Preloader.js b/src/libs/cocos2d/Preloader.js new file mode 100644 index 0000000..8061e8e --- /dev/null +++ b/src/libs/cocos2d/Preloader.js @@ -0,0 +1,72 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + events = require('events'); + +var Preloader = BObject.extend(/** @lends cocos.Preloader# */{ + /** + * Total number of resources. + * @type Integer + */ + count: -1, + + /** + * Number of resources that have finished loading + * @type Integer + */ + loaded: 0, + + _listeners: null, + + /** + * @class Preloads all remote resources + * @memberOf cocos + * @extends BObject + * @constructs + */ + init: function (opts) { + Preloader.superclass.init.call(this, opts); + + this._listeners = {}; + this.set('count', Object.keys(__remote_resources__).length); + }, + + load: function() { + this.set('loaded', 0); + this.set('count', Object.keys(__remote_resources__).length); + + for (var uri in __remote_resources__) { + if (__remote_resources__.hasOwnProperty(uri)) { + if (__resources__[uri]) { + // Already loaded + this.didLoadResource(uri); + continue; + } + var file = resource(uri); + + // Notify when a resource has loaded + this._listeners[uri] = events.addListener(file, 'load', util.callback(this, (function(uri) { + return function () { this.didLoadResource(uri); }; + })(uri))); + + file.load() + } + } + }, + + didLoadResource: function(uri) { + this.set('loaded', this.get('loaded') +1); + if (this._listeners[uri]) { + events.removeListener(this._listeners[uri]); + } + events.trigger(this, 'load', uri, this); + + if (this.get('loaded') >= this.get('count')) { + events.trigger(this, 'complete', this); + } + } +}); + +exports.Preloader = Preloader; diff --git a/src/libs/cocos2d/RemoteImage.js b/src/libs/cocos2d/RemoteImage.js new file mode 100644 index 0000000..956fcdc --- /dev/null +++ b/src/libs/cocos2d/RemoteImage.js @@ -0,0 +1,43 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + events = require('events'), + RemoteResource = require('./RemoteResource').RemoteResource; + +var RemoteImage = RemoteResource.extend(/** @lends cocos.RemoteImage# */{ + /** + * @memberOf cocos + * @extends cocos.RemoteResource + * @constructs + */ + init: function (opts) { + RemoteImage.superclass.init.call(this, opts); + }, + + /** + * Load a remote image + * @returns Image + */ + load: function () { + var img = new Image(); + var self = this; + img.onload = function () { + var path = self.get('path'); + + var r = __remote_resources__[path]; + __resources__[path] = util.copy(r); + __resources__[path].data = img; + __resources__[path].meta.remote = true; + + events.trigger(self, 'load', self); + }; + + img.src = this.get('url'); + + return img; + } +}); + +exports.RemoteImage = RemoteImage; diff --git a/src/libs/cocos2d/RemoteResource.js b/src/libs/cocos2d/RemoteResource.js new file mode 100644 index 0000000..0abe55f --- /dev/null +++ b/src/libs/cocos2d/RemoteResource.js @@ -0,0 +1,59 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + events = require('events'); + +var RemoteResource = BObject.extend(/** @lends cocos.RemoteResource# */{ + /** + * The URL to the remote resource + * @type String + */ + url: null, + + /** + * The path used to reference the resource in the app + * @type String + */ + path: null, + + /** + * @memberOf cocos + * @extends BObject + * @constructs + */ + init: function (opts) { + RemoteResource.superclass.init.call(this, opts); + + this.set('url', opts.url); + this.set('path', opts.path); + + }, + + /** + * Load the remote resource via ajax + */ + load: function () { + var xhr = new XMLHttpRequest(); + var self = this; + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + var path = self.get('path'); + + var r = __remote_resources__[path]; + __resources__[path] = util.copy(r); + __resources__[path].data = xhr.responseText; + __resources__[path].meta.remote = true; + + events.trigger(self, 'load', self); + } + }; + + xhr.open('GET', this.get('url'), true); + xhr.send(null); + } +}); + + +exports.RemoteResource = RemoteResource; diff --git a/src/libs/cocos2d/Scheduler.js b/src/libs/cocos2d/Scheduler.js index 5e3229f..46fce24 100644 --- a/src/libs/cocos2d/Scheduler.js +++ b/src/libs/cocos2d/Scheduler.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'); /** @ignore */ @@ -33,18 +37,18 @@ var Timer = BObject.extend(/** @lends cocos.Timer# */{ * @opt {Function} callback The function to run at each interval * @opt {Float} interval Number of milliseconds to wait between each exectuion of callback */ - init: function(opts) { - @super; + init: function (opts) { + Timer.superclass.init(this, opts); - this.set('callback', opts['callback']); - this.set('interval', opts['interval'] || 0); + this.set('callback', opts.callback); + this.set('interval', opts.interval || 0); this.set('elapsed', -1); }, /** * @private */ - update: function(dt) { + update: function (dt) { if (this.elapsed == -1) { this.elapsed = 0; } else { @@ -76,7 +80,7 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ * @singleton * @private */ - init: function() { + init: function () { this.updates0 = []; this.updatesNeg = []; this.updatesPos = []; @@ -84,16 +88,22 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ this.hashForMethods = {}; }, - schedule: function(opts) { - var target = opts['target'], - method = opts['method'], - interval = opts['interval'], - paused = opts['paused'] || false; + /** + * The scheduled method will be called every 'interval' seconds. + * If paused is YES, then it won't be called until it is resumed. + * If 'interval' is 0, it will be called every frame, but if so, it recommened to use 'scheduleUpdateForTarget:' instead. + * If the selector is already scheduled, then only the interval parameter will be updated without re-scheduling it again. + */ + schedule: function (opts) { + var target = opts.target, + method = opts.method, + interval = opts.interval, + paused = opts.paused || false; var element = this.hashForMethods[target.get('id')]; if (!element) { - element = new HashMethodEntry; + element = new HashMethodEntry(); this.hashForMethods[target.get('id')] = element; element.target = target; element.paused = paused; @@ -105,18 +115,24 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ element.timers.push(timer); }, - scheduleUpdate: function(opts) { - var target = opts['target'], - priority = opts['priority'], - paused = opts['paused']; + /** + * Schedules the 'update' selector for a given target with a given priority. + * The 'update' selector will be called every frame. + * The lower the priority, the earlier it is called. + */ + scheduleUpdate: function (opts) { + var target = opts.target, + priority = opts.priority, + paused = opts.paused; + var i, len; var entry = {target: target, priority: priority, paused: paused}; var added = false; - if (priority == 0) { + if (priority === 0) { this.updates0.push(entry); } else if (priority < 0) { - for (var i = 0, len = this.updatesNeg.length; i < len; i++) { + for (i = 0, len = this.updatesNeg.length; i < len; i++) { if (priority < this.updatesNeg[i].priority) { this.updatesNeg.splice(i, 0, entry); added = true; @@ -128,7 +144,7 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ this.updatesNeg.push(entry); } } else /* priority > 0 */{ - for (var i = 0, len = this.updatesPos.length; i < len; i++) { + for (i = 0, len = this.updatesPos.length; i < len; i++) { if (priority < this.updatesPos[i].priority) { this.updatesPos.splice(i, 0, entry); added = true; @@ -144,41 +160,163 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ this.hashForUpdates[target.get('id')] = entry; }, - tick: function(dt) { + /** + * 'tick' the scheduler. + * You should NEVER call this method, unless you know what you are doing. + */ + tick: function (dt) { + var i, len, x; if (this.timeScale != 1.0) { dt *= this.timeScale; } var entry; - for (var i = 0, len = this.updatesNeg.length; i < len; i++) { + for (i = 0, len = this.updatesNeg.length; i < len; i++) { entry = this.updatesNeg[i]; - if (!entry.paused) entry.target.update(dt); + if (entry && !entry.paused) { + entry.target.update(dt); + } } - for (var i = 0, len = this.updates0.length; i < len; i++) { + for (i = 0, len = this.updates0.length; i < len; i++) { entry = this.updates0[i]; - if (!entry.paused) entry.target.update(dt); + if (entry && !entry.paused) { + entry.target.update(dt); + } } - for (var i = 0, len = this.updatesPos.length; i < len; i++) { + for (i = 0, len = this.updatesPos.length; i < len; i++) { entry = this.updatesPos[i]; - if (!entry.paused) entry.target.update(dt); + if (entry && !entry.paused) { + entry.target.update(dt); + } } - for (var x in this.hashForMethods) { - var entry = this.hashForMethods[x]; - for (var i = 0, len = entry.timers.length; i < len; i++) { - var timer = entry.timers[i]; - timer.update(dt); + for (x in this.hashForMethods) { + if (this.hashForMethods.hasOwnProperty(x)) { + entry = this.hashForMethods[x]; + + if (entry) { + for (i = 0, len = entry.timers.length; i < len; i++) { + var timer = entry.timers[i]; + if (timer) { + timer.update(dt); + } + } + } } } - }, + }, - unscheduleAllSelectorsForTarget: function(target) { + /** + * Unshedules a selector for a given target. + * If you want to unschedule the "update", use unscheduleUpdateForTarget. + */ + unschedule: function (opts) { + if (!opts.target || !opts.method) { + return; + } + var element = this.hashForMethods[opts.target.get('id')]; + if (element) { + for (var i=0; i 0 */{ + this.updatesPos.splice(this.updatesPos.indexOf(elementUpdate), 1); + } + } + // Release HashMethodEntry object + this.hashForUpdates[id] = null; + }, + + /** + * Unschedules all selectors from all targets. + * You should NEVER call this method, unless you know what you are doing. + */ + unscheduleAllSelectors: function () { + var i, x, entry; + + // Custom selectors + for (x in this.hashForMethods) { + if (this.hashForMethods.hasOwnProperty(x)) { + entry = this.hashForMethods[x]; + this.unscheduleAllSelectorsForTarget(entry.target); + } + } + // Updates selectors + for (i = 0, len = this.updatesNeg.length; i < len; i++) { + entry = this.updatesNeg[i]; + if (entry) { + this.unscheduleUpdateForTarget(entry.target); + } + } + + for (i = 0, len = this.updates0.length; i < len; i++) { + entry = this.updates0[i]; + if (entry) { + this.unscheduleUpdateForTarget(entry.target); + } + } + + for (i = 0, len = this.updatesPos.length; i < len; i++) { + entry = this.updatesPos[i]; + if (entry) { + this.unscheduleUpdateForTarget(entry.target); + } + } + }, + + /** + * Unschedules all selectors for a given target. + * This also includes the "update" selector. + */ + unscheduleAllSelectorsForTarget: function (target) { + if (!target) { + return; + } + // Custom selector + var element = this.hashForMethods[target.get('id')]; + if (element) { + element.paused = true; + element.timers = []; // Clear all timers + } + // Release HashMethodEntry object + this.hashForMethods[target.get('id')] = null; + + // Update selector + this.unscheduleUpdateForTarget(target); + }, + + /** + * Pauses the target. + * All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed. + * If the target is not present, nothing happens. + */ + + pauseTarget: function (target) { var element = this.hashForMethods[target.get('id')]; if (element) { element.paused = true; @@ -190,7 +328,13 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ } }, - resumeTarget: function(target) { + /** + * Resumes the target. + * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again. + * If the target is not present, nothing happens. + */ + + resumeTarget: function (target) { var element = this.hashForMethods[target.get('id')]; if (element) { element.paused = false; @@ -201,7 +345,7 @@ var Scheduler = BObject.extend(/** @lends cocos.Scheduler# */{ if (elementUpdate) { elementUpdate.paused = false; } - } + } }); util.extend(Scheduler, /** @lends cocos.Scheduler */{ @@ -210,7 +354,7 @@ util.extend(Scheduler, /** @lends cocos.Scheduler */{ * @getter sharedScheduler * @type cocos.Scheduler */ - get_sharedScheduler: function(key) { + get_sharedScheduler: function (key) { if (!this._instance) { this._instance = this.create(); } diff --git a/src/libs/cocos2d/SpriteFrame.js b/src/libs/cocos2d/SpriteFrame.js index 0b327fc..f1d368d 100644 --- a/src/libs/cocos2d/SpriteFrame.js +++ b/src/libs/cocos2d/SpriteFrame.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), geo = require('geometry'), ccp = geo.ccp; @@ -28,20 +32,20 @@ var SpriteFrame = BObject.extend(/** @lends cocos.SpriteFrame# */{ * @opt {cocos.Texture2D} texture The texture to draw this frame using * @opt {geometry.Rect} rect The rectangle inside the texture to draw */ - init: function(opts) { - @super; - - this.texture = opts['texture']; - this.rect = opts['rect']; - this.rotated = !!opts['rotate']; - this.offset = opts['offset'] || ccp(0, 0); - this.originalSize = opts['originalSize'] || util.copy(this.rect.size); + init: function (opts) { + SpriteFrame.superclass.init(this, opts); + + this.texture = opts.texture; + this.rect = opts.rect; + this.rotated = !!opts.rotate; + this.offset = opts.offset || ccp(0, 0); + this.originalSize = opts.originalSize || util.copy(this.rect.size); }, /** * @ignore */ - toString: function() { + toString: function () { return "[object SpriteFrame | TextureName=" + this.texture.get('name') + ", Rect = (" + this.rect.origin.x + ", " + this.rect.origin.y + ", " + this.rect.size.width + ", " + this.rect.size.height + ")]"; }, @@ -50,7 +54,7 @@ var SpriteFrame = BObject.extend(/** @lends cocos.SpriteFrame# */{ * * @returns {cocos.SpriteFrame} Exact copy of this object */ - copy: function() { + copy: function () { return SpriteFrame.create({rect: this.rect, rotated: this.rotated, offset: this.offset, originalSize: this.originalSize, texture: this.texture}); } diff --git a/src/libs/cocos2d/SpriteFrameCache.js b/src/libs/cocos2d/SpriteFrameCache.js index 7349f70..d83c654 100644 --- a/src/libs/cocos2d/SpriteFrameCache.js +++ b/src/libs/cocos2d/SpriteFrameCache.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), geo = require('geometry'), Plist = require('Plist').Plist, @@ -24,8 +28,8 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ * @constructs * @singleton */ - init: function() { - @super; + init: function () { + SpriteFrameCache.superclass.init.call(this); this.set('spriteFrames', {}); this.set('spriteFrameAliases', {}); @@ -36,8 +40,8 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ * * @param {String} opts.file The filename of a Zwoptex .plist containing the frame definiitons. */ - addSpriteFrames: function(opts) { - var plistPath = opts['file'], + addSpriteFrames: function (opts) { + var plistPath = opts.file, plist = Plist.create({file: plistPath}), plistData = plist.get('data'); @@ -48,10 +52,10 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ var format = 0, texturePath = null; - if (metaDataDict != null) { + if (metaDataDict) { format = metaDataDict.format; // Get texture path from meta data - texturePath = metaDataDict.textureFileName + texturePath = metaDataDict.textureFileName; } if (!texturePath) { @@ -70,7 +74,7 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ switch (format) { case 0: - var x = frameDict.x + var x = frameDict.x, y = frameDict.y, w = frameDict.width, h = frameDict.height, @@ -80,10 +84,14 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ oh = frameDict.originalHeight; // check ow/oh - if(!ow || !oh) { + if (!ow || !oh) { //console.log("cocos2d: WARNING: originalWidth/Height not found on the CCSpriteFrame. AnchorPoint won't work as expected. Regenerate the .plist"); } + if (FLIP_Y_AXIS) { + oy *= -1; + } + // abs ow/oh ow = Math.abs(ow); oh = Math.abs(oh); @@ -103,6 +111,10 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ offset = geo.pointFromString(frameDict.offset), sourceSize = geo.sizeFromString(frameDict.sourceSize); + if (FLIP_Y_AXIS) { + offset.y *= -1; + } + // create frame spriteFrame = SpriteFrame.create({texture: texture, @@ -119,6 +131,11 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ textureRect = geo.rectFromString(frameDict.textureRect), textureRotated = frameDict.textureRotated; + + if (FLIP_Y_AXIS) { + spriteOffset.y *= -1; + } + // get aliases var aliases = frameDict.aliases; for (var i = 0, len = aliases.length; i < len; i++) { @@ -135,7 +152,7 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ break; default: - throw "Unsupported Zwoptex format: " + format + throw "Unsupported Zwoptex format: " + format; } // Add sprite frame @@ -150,8 +167,8 @@ var SpriteFrameCache = BObject.extend(/** @lends cocos.SpriteFrameCache# */{ * @param {String} opts.name The name of the sprite frame * @returns {cocos.SpriteFrame} The sprite frame */ - getSpriteFrame: function(opts) { - var name = opts['name']; + getSpriteFrame: function (opts) { + var name = opts.name; var frame = this.get('spriteFrames')[name]; @@ -181,7 +198,7 @@ util.extend(SpriteFrameCache, /** @lends cocos.SpriteFrameCache */{ * @name cocos.SpriteFrameCache.sharedSpriteFrameCache * @type cocos.SpriteFrameCache */ - get_sharedSpriteFrameCache: function(key) { + get_sharedSpriteFrameCache: function (key) { if (!this._instance) { this._instance = this.create(); } diff --git a/src/libs/cocos2d/TMXOrientation.js b/src/libs/cocos2d/TMXOrientation.js index 5da468b..347b85a 100644 --- a/src/libs/cocos2d/TMXOrientation.js +++ b/src/libs/cocos2d/TMXOrientation.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + /** * @memberOf cocos * @namespace @@ -7,19 +11,19 @@ var TMXOrientation = /** @lends cocos.TMXOrientation */{ * Orthogonal orientation * @constant */ - TMXOrientationOrtho: 1, + TMXOrientationOrtho: 1, /** * Hexagonal orientation * @constant */ - TMXOrientationHex: 2, + TMXOrientationHex: 2, /** * Isometric orientation * @constant */ - TMXOrientationIso: 3 + TMXOrientationIso: 3 }; module.exports = TMXOrientation; diff --git a/src/libs/cocos2d/TMXXMLParser.js b/src/libs/cocos2d/TMXXMLParser.js index 6718a2e..1bb6fd8 100644 --- a/src/libs/cocos2d/TMXXMLParser.js +++ b/src/libs/cocos2d/TMXXMLParser.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray DOMParser console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), path = require('path'), ccp = require('geometry').ccp, @@ -7,6 +11,132 @@ var util = require('util'), TMXOrientationHex = require('./TMXOrientation').TMXOrientationHex, TMXOrientationIso = require('./TMXOrientation').TMXOrientationIso; +var TMXTilesetInfo = BObject.extend(/** @lends cocos.TMXTilesetInfo# */{ + name: '', + firstGID: 0, + tileSize: null, + spacing: 0, + margin: 0, + sourceImage: null, + + /** + * @memberOf cocos + * @constructs + * @extends BObject + */ + init: function () { + TMXTilesetInfo.superclass.init.call(this); + }, + + rectForGID: function (gid) { + var rect = {size: {}, origin: ccp(0, 0)}; + rect.size = util.copy(this.tileSize); + + gid = gid - this.firstGID; + + var imgSize = this.get('imageSize'); + + var maxX = Math.floor((imgSize.width - this.margin * 2 + this.spacing) / (this.tileSize.width + this.spacing)); + + rect.origin.x = (gid % maxX) * (this.tileSize.width + this.spacing) + this.margin; + rect.origin.y = Math.floor(gid / maxX) * (this.tileSize.height + this.spacing) + this.margin; + + return rect; + } +}); + +var TMXLayerInfo = BObject.extend(/** @lends cocos.TMXLayerInfo# */{ + name: '', + layerSize: null, + tiles: null, + visible: true, + opacity: 255, + minGID: 100000, + maxGID: 0, + properties: null, + offset: null, + + /** + * @memberOf cocos + * @constructs + * @extends BObject + */ + init: function () { + TMXLayerInfo.superclass.init.call(this); + + this.properties = {}; + this.offset = ccp(0, 0); + } +}); + +var TMXObjectGroup = BObject.extend(/** @lends cocos.TMXObjectGroup# */{ + name: '', + properties: null, + offset: null, + objects: null, + + /** + * @memberOf cocos + * @constructs + * @extends BObject + */ + init: function () { + TMXObjectGroup.superclass.init.call(this); + + this.properties = {}; + this.objects = {}; + this.offset = ccp(0, 0); + }, + + /** + * Get the value for the specific property name + * + * @opt {String} name Property name + * @returns {String} Property value + */ + getProperty: function (opts) { + var propertyName = opts.name; + return this.properties[propertyName]; + }, + + /** + * @deprected Since v0.2. You should now use cocos.TMXObjectGroup#getProperty + */ + propertyNamed: function (opts) { + console.warn('TMXObjectGroup#propertyNamed is deprected. Use TMXTiledMap#getProperty instread'); + return this.getProperty(opts); + }, + + /** + * Get the object for the specific object name. It will return the 1st + * object found on the array for the given name. + * + * @opt {String} name Object name + * @returns {Object} Object + */ + getObject: function (opts) { + var objectName = opts.name; + var object = null; + + this.objects.forEach(function (item) { + if (item.name == objectName) { + object = item; + } + }); + if (object !== null) { + return object; + } + }, + + /** + * @deprected Since v0.2. You should now use cocos.TMXObjectGroup#getProperty + */ + objectNamed: function (opts) { + console.warn('TMXObjectGroup#objectNamed is deprected. Use TMXObjectGroup#getObject instread'); + return this.getObject(opts); + } +}); + var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ filename: '', orientation: 0, @@ -25,7 +155,9 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ * * @param {String} tmxFile The file path of the TMX file to load */ - init: function(tmxFile) { + init: function (tmxFile) { + TMXMapInfo.superclass.init.call(this, tmxFile); + this.tilesets = []; this.layers = []; this.objectGroups = []; @@ -36,7 +168,7 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ this.parseXMLFile(tmxFile); }, - parseXMLFile: function(xmlFile) { + parseXMLFile: function (xmlFile) { var parser = new DOMParser(), doc = parser.parseFromString(resource(xmlFile), 'text/xml'); @@ -48,24 +180,23 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ case 'orthogonal': this.orientation = TMXOrientationOrtho; break; - /* case 'isometric': this.orientation = TMXOrientationIso; break; case 'hexagonal': this.orientation = TMXOrientationHex; break; - */ default: throw "cocos2d: TMXFomat: Unsupported orientation: " + map.getAttribute('orientation'); } - this.mapSize = {width: parseInt(map.getAttribute('width'), 10), height: parseInt(map.getAttribute('height'), 10)} - this.tileSize = {width: parseInt(map.getAttribute('tilewidth'), 10), height: parseInt(map.getAttribute('tileheight'), 10)} + this.mapSize = {width: parseInt(map.getAttribute('width'), 10), height: parseInt(map.getAttribute('height'), 10)}; + this.tileSize = {width: parseInt(map.getAttribute('tilewidth'), 10), height: parseInt(map.getAttribute('tileheight'), 10)}; // PARSE var tilesets = map.getElementsByTagName('tileset'); - for (var i = 0, len = tilesets.length; i < len; i++) { + var i, j, len, jen, s; + for (i = 0, len = tilesets.length; i < len; i++) { var t = tilesets[i]; var tileset = TMXTilesetInfo.create(); @@ -78,9 +209,9 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ tileset.set('margin', parseInt(t.getAttribute('margin'), 10)); } - var s = {}; - s.width = parseInt(t.getAttribute('tilewidth'), 10) - s.height = parseInt(t.getAttribute('tileheight'), 10) + s = {}; + s.width = parseInt(t.getAttribute('tilewidth'), 10); + s.height = parseInt(t.getAttribute('tileheight'), 10); tileset.set('tileSize', s); // PARSE We assume there's only 1 @@ -88,30 +219,29 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ tileset.set('sourceImage', path.join(path.dirname(this.filename), image.getAttribute('source'))); this.tilesets.push(tileset); - delete tileset; } // PARSE var layers = map.getElementsByTagName('layer'); - for (var i = 0, len = layers.length; i < len; i++) { + for (i = 0, len = layers.length; i < len; i++) { var l = layers[i]; var data = l.getElementsByTagName('data')[0]; var layer = TMXLayerInfo.create(); layer.set('name', l.getAttribute('name')); - if (l.getAttribute('visible') == undefined) { + if (l.getAttribute('visible') !== false) { layer.set('visible', true); } else { - layer.set('visible', !!parseInt(l.getAttribute('visible'))); + layer.set('visible', !!parseInt(l.getAttribute('visible'), 10)); } - var s = {}; - s.width = parseInt(l.getAttribute('width'), 10) - s.height = parseInt(l.getAttribute('height'), 10) + s = {}; + s.width = parseInt(l.getAttribute('width'), 10); + s.height = parseInt(l.getAttribute('height'), 10); layer.set('layerSize', s); var opacity = l.getAttribute('opacity'); - if (opacity == undefined) { + if (!opacity && opacity !== 0) { layer.set('opacity', 255); } else { layer.set('opacity', 255 * parseFloat(opacity)); @@ -119,8 +249,12 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ var x = parseInt(l.getAttribute('x'), 10), y = parseInt(l.getAttribute('y'), 10); - if (isNaN(x)) x = 0; - if (isNaN(y)) y = 0; + if (isNaN(x)) { + x = 0; + } + if (isNaN(y)) { + y = 0; + } layer.set('offset', ccp(x, y)); @@ -128,85 +262,98 @@ var TMXMapInfo = BObject.extend(/** @lends cocos.TMXMapInfo# */{ // nodes up into multiple nodes. So, we'll stitch them back // together. var nodeValue = ''; - for (var j = 0, jen = data.childNodes.length; j < jen; j++) { + for (j = 0, jen = data.childNodes.length; j < jen; j++) { nodeValue += data.childNodes[j].nodeValue; } // Unpack the tilemap data - if (data.getAttribute('compression') == 'gzip') { + var compression = data.getAttribute('compression'); + switch (compression) { + case 'gzip': layer.set('tiles', gzip.unzipBase64AsArray(nodeValue, 4)); - } else { + break; + + // Uncompressed + case null: + case '': layer.set('tiles', base64.decodeAsArray(nodeValue, 4)); + break; + + default: + throw "Unsupported TMX Tile Map compression: " + compression; } this.layers.push(layer); - delete layer; - } // TODO PARSE - } -}); - -var TMXLayerInfo = BObject.extend(/** @lends cocos.TMXLayerInfo# */{ - name: '', - layerSize: null, - tiles: null, - visible: true, - opacity: 255, - minGID: 100000, - maxGID: 0, - properties: null, - offset: null, - - /** - * @memberOf cocos - * @constructs - * @extends BObject - */ - init: function() { - @super; - - this.properties = {}; - this.offset = ccp(0, 0); - } -}); + // PARSE + var objectgroups = map.getElementsByTagName('objectgroup'); + for (i = 0, len = objectgroups.length; i < len; i++) { + var g = objectgroups[i], + objectGroup = TMXObjectGroup.create(); + + objectGroup.set('name', g.getAttribute('name')); + + var properties = g.querySelectorAll('objectgroup > properties property'), + propertiesValue = {}, + property; + + for (j = 0; j < properties.length; j++) { + property = properties[j]; + if (property.getAttribute('name')) { + propertiesValue[property.getAttribute('name')] = property.getAttribute('value'); + } + } + + objectGroup.set('properties', propertiesValue); + + var objectsArray = [], + objects = g.querySelectorAll('object'); + + for (j = 0; j < objects.length; j++) { + var object = objects[j]; + var objectValue = { + x : parseInt(object.getAttribute('x'), 10), + y : parseInt(object.getAttribute('y'), 10), + width : parseInt(object.getAttribute('width'), 10), + height : parseInt(object.getAttribute('height'), 10) + }; + if (object.getAttribute('name')) { + objectValue.name = object.getAttribute('name'); + } + if (object.getAttribute('type')) { + objectValue.type = object.getAttribute('type'); + } + properties = object.querySelectorAll('property'); + for (var k = 0; k < properties.length; k++) { + property = properties[k]; + if (property.getAttribute('name')) { + objectValue[property.getAttribute('name')] = property.getAttribute('value'); + } + } + objectsArray.push(objectValue); -var TMXTilesetInfo = BObject.extend(/** @lends cocos.TMXTilesetInfo# */{ - name: '', - firstGID: 0, - tileSize: null, - spacing: 0, - margin: 0, - sourceImage: null, + } + objectGroup.set('objects', objectsArray); + this.objectGroups.push(objectGroup); + } - /** - * @memberOf cocos - * @constructs - * @extends BObject - */ - init: function() { - @super; - }, - rectForGID: function(gid) { - var rect = {size:{}, origin:ccp(0,0)}; - rect.size = util.copy(this.tileSize); - - gid = gid - this.firstGID; + // PARSE + var properties = doc.querySelectorAll('map > properties > property'); - var imgSize = this.get('imageSize'); - - var max_x = Math.floor((imgSize.width - this.margin*2 + this.spacing) / (this.tileSize.width + this.spacing)); - - rect.origin.x = (gid % max_x) * (this.tileSize.width + this.spacing) + this.margin; - rect.origin.y = Math.floor(gid / max_x) * (this.tileSize.height + this.spacing) + this.margin; - - return rect; + for (i = 0; i < properties.length; i++) { + var property = properties[i]; + if (property.getAttribute('name')) { + this.properties[property.getAttribute('name')] = property.getAttribute('value'); + } + } } }); exports.TMXMapInfo = TMXMapInfo; exports.TMXLayerInfo = TMXLayerInfo; exports.TMXTilesetInfo = TMXTilesetInfo; +exports.TMXObjectGroup = TMXObjectGroup; diff --git a/src/libs/cocos2d/Texture2D.js b/src/libs/cocos2d/Texture2D.js index 346491c..875ca57 100644 --- a/src/libs/cocos2d/Texture2D.js +++ b/src/libs/cocos2d/Texture2D.js @@ -1,9 +1,16 @@ -var util = require('util'); +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + events = require('events'), + RemoteResource = require('./RemoteResource').RemoteResource; var Texture2D = BObject.extend(/** @lends cocos.Texture2D# */{ - imgElement: null, - size: null, + imgElement: null, + size: null, name: null, + isLoaded: false, /** * @memberOf cocos @@ -13,49 +20,74 @@ var Texture2D = BObject.extend(/** @lends cocos.Texture2D# */{ * @opt {String} [file] The file path of the image to use as a texture * @opt {Texture2D|HTMLImageElement} [data] Image data to read from */ - init: function(opts) { - var file = opts['file'], - data = opts['data'], - texture = opts['texture']; + init: function (opts) { + var file = opts.file, + data = opts.data, + texture = opts.texture; - if (file) { + if (file) { this.name = file; - data = resource(file); - } else if (texture) { + data = resource(file); + } else if (texture) { this.name = texture.get('name'); - data = texture.get('imgElement'); - } + data = texture.get('imgElement'); + } + + this.size = {width: 0, height: 0}; - this.size = {width: 0, height: 0}; + if (data instanceof RemoteResource) { + events.addListener(data, 'load', util.callback(this, this.dataDidLoad)); + this.set('imgElement', data.load()); + } else { + this.set('imgElement', data); + this.dataDidLoad(data); + } + }, - this.set('imgElement', data); - this.set('size', {width:this.imgElement.width, height: this.imgElement.height}); - }, + dataDidLoad: function (data) { + this.isLoaded = true; + this.set('size', {width: this.imgElement.width, height: this.imgElement.height}); + events.trigger(self, 'load', self); + }, - drawAtPoint: function(ctx, point) { - ctx.drawImage(this.imgElement, point.x, point.y); - }, - drawInRect: function(ctx, rect) { - ctx.drawImage(this.imgElement, - rect.origin.x, rect.origin.y, - rect.size.width, rect.size.height - ); - }, + drawAtPoint: function (ctx, point) { + if (!this.isLoaded) { + return; + } + ctx.drawImage(this.imgElement, point.x, point.y); + }, + drawInRect: function (ctx, rect) { + if (!this.isLoaded) { + return; + } + ctx.drawImage(this.imgElement, + rect.origin.x, rect.origin.y, + rect.size.width, rect.size.height + ); + }, /** * @getter data * @type {String} Base64 encoded image data */ - get_data: function() { + get_data: function () { return this.imgElement ? this.imgElement.src : null; - }, + }, /** * @getter contentSize * @type {geometry.Size} Size of the texture */ - get_contentSize: function() { - return this.size; + get_contentSize: function () { + return this.size; + }, + + get_pixelsWide: function () { + return this.size.width; + }, + + get_pixelsHigh: function () { + return this.size.height; } }); diff --git a/src/libs/cocos2d/TextureAtlas.js b/src/libs/cocos2d/TextureAtlas.js index ea92d15..3a53b13 100644 --- a/src/libs/cocos2d/TextureAtlas.js +++ b/src/libs/cocos2d/TextureAtlas.js @@ -1,18 +1,22 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - Texture2D = require('./Texture2D').Texture2D; + Texture2D = require('./Texture2D').Texture2D; /* QUAD STRUCTURE quad = { - drawRect: , // Where the quad is drawn to - textureRect: // The slice of the texture to draw in drawRect + drawRect: , // Where the quad is drawn to + textureRect: // The slice of the texture to draw in drawRect } */ var TextureAtlas = BObject.extend(/** @lends cocos.TextureAtlas# */{ - quads: null, - imgElement: null, - texture: null, + quads: null, + imgElement: null, + texture: null, /** * A single texture that can represent lots of smaller images @@ -25,46 +29,48 @@ var TextureAtlas = BObject.extend(/** @lends cocos.TextureAtlas# */{ * @opt {Texture2D|HTMLImageElement} [data] Image data to read from * @opt {CanvasElement} [canvas] A canvas to use as a texture */ - init: function(opts) { - var file = opts['file'], - data = opts['data'], - texture = opts['texture'], - canvas = opts['canvas']; + init: function (opts) { + var file = opts.file, + data = opts.data, + texture = opts.texture, + canvas = opts.canvas; if (canvas) { // If we've been given a canvas element then we'll use that for our image this.imgElement = canvas; } else { - var texture = Texture2D.create({texture: texture, file: file, data: data}); - this.set('texture', texture); - this.imgElement = texture.get('imgElement'); + texture = Texture2D.create({texture: texture, file: file, data: data}); + this.set('texture', texture); + this.imgElement = texture.get('imgElement'); } - this.quads = []; - }, + this.quads = []; + }, - insertQuad: function(opts) { - var quad = opts['quad'], - index = opts['index'] || 0; + insertQuad: function (opts) { + var quad = opts.quad, + index = opts.index || 0; - this.quads.splice(index, 0, quad); - }, - removeQuad: function(opts) { - var index = opts['index']; + this.quads.splice(index, 0, quad); + }, + removeQuad: function (opts) { + var index = opts.index; - this.quads.splice(index, 1); - }, + this.quads.splice(index, 1); + }, - drawQuads: function(ctx) { - util.each(this.quads, util.callback(this, function(quad) { - if (!quad) return; + drawQuads: function (ctx) { + util.each(this.quads, util.callback(this, function (quad) { + if (!quad) { + return; + } - this.drawQuad(ctx, quad); - })); - }, + this.drawQuad(ctx, quad); + })); + }, - drawQuad: function(ctx, quad) { + drawQuad: function (ctx, quad) { var sx = quad.textureRect.origin.x, sy = quad.textureRect.origin.y, sw = quad.textureRect.size.width, @@ -75,30 +81,37 @@ var TextureAtlas = BObject.extend(/** @lends cocos.TextureAtlas# */{ dw = quad.drawRect.size.width, dh = quad.drawRect.size.height; + var scaleX = 1; var scaleY = 1; + + if (FLIP_Y_AXIS) { + dy -= dh; + dh *= -1; + } + if (dw < 0) { - dw *= -1 + dw *= -1; scaleX = -1; } if (dh < 0) { - dh *= -1 + dh *= -1; scaleY = -1; } ctx.scale(scaleX, scaleY); var img = this.get('imgElement'); - ctx.drawImage(img, - sx, sy, // Draw slice from x,y - sw, sh, // Draw slice size - dx, dy, // Draw at 0, 0 - dw, dh // Draw size - ); + ctx.drawImage(img, + sx, sy, // Draw slice from x,y + sw, sh, // Draw slice size + dx, dy, // Draw at 0, 0 + dw, dh // Draw size + ); ctx.scale(1, 1); - } + } }); -exports.TextureAtlas = TextureAtlas +exports.TextureAtlas = TextureAtlas; diff --git a/src/libs/cocos2d/actions/Action.js b/src/libs/cocos2d/actions/Action.js index 2655cc9..47d82cd 100644 --- a/src/libs/cocos2d/actions/Action.js +++ b/src/libs/cocos2d/actions/Action.js @@ -1,5 +1,11 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - console = require('system').console; + console = require('system').console, + geo = require('geometry'), + ccp = geo.ccp; /** * @memberOf cocos.actions @@ -9,19 +15,25 @@ var util = require('util'), */ var Action = BObject.extend(/** @lends cocos.actions.Action# */{ /** - * The cocos.Node the action is being performed on + * The Node the action is being performed on * @type cocos.nodes.Node */ target: null, originalTarget: null, - + + /** + * Unique tag to identify the action + * @type * + */ + tag: null, + /** * Called every frame with it's delta time. * * @param {Float} dt The delta time */ - step: function(dt) { - console.log('Action.step() Override me'); + step: function (dt) { + window.console.warn("Action.step() Override me"); }, /** @@ -29,8 +41,8 @@ var Action = BObject.extend(/** @lends cocos.actions.Action# */{ * * @param {Float} time How much of the animation has played. 0.0 = just started, 1.0 just finished. */ - update: function(time) { - console.log('Action.update() Override me'); + update: function (time) { + window.console.warn("Action.update() Override me"); }, /** @@ -38,16 +50,16 @@ var Action = BObject.extend(/** @lends cocos.actions.Action# */{ * * @param {cocos.nodes.Node} target The Node to run the action on */ - startWithTarget: function(target) { + startWithTarget: function (target) { this.target = this.originalTarget = target; }, /** * Called after the action has finished. It will set the 'target' to nil. - * Important: You should never call cocos.Action#stop manually. - * Instead, use cocos.Node#stopAction(action) + * Important: You should never call cocos.actions.Action#stop manually. + * Instead, use cocos.nodes.Node#stopAction(action) */ - stop: function() { + stop: function () { this.target = null; }, @@ -55,7 +67,7 @@ var Action = BObject.extend(/** @lends cocos.actions.Action# */{ * @getter isDone * @type {Boolean} */ - get_isDone: function(key) { + get_isDone: function (key) { return true; }, @@ -65,38 +77,34 @@ var Action = BObject.extend(/** @lends cocos.actions.Action# */{ * * @returns {cocos.actions.Action} A new Action in reverse */ - reverse: function() { + reverse: function () { } }); -/** - * - * Repeats an action forever. To repeat the an action for a limited number of - * times use the cocos.Repeat action. - */ var RepeatForever = Action.extend(/** @lends cocos.actions.RepeatForever# */{ other: null, /** * @memberOf cocos.actions + * @class Repeats an action forever. To repeat the an action for a limited + * number of times use the cocos.Repeat action. * @extends cocos.actions.Action - * @constructs * @param {cocos.actions.Action} action An action to repeat forever + * @constructs */ - init: function(action) { - - @super(); + init: function (action) { + RepeatForever.superclass.init(this, action); this.other = action; }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + RepeatForever.superclass.startWithTarget.call(this, target); this.other.startWithTarget(this.target); }, - step: function(dt) { + step: function (dt) { this.other.step(dt); if (this.other.get('isDone')) { var diff = dt - this.other.get('duration') - this.other.get('elapsed'); @@ -106,15 +114,15 @@ var RepeatForever = Action.extend(/** @lends cocos.actions.RepeatForever# */{ } }, - get_isDone: function() { + get_isDone: function () { return false; }, - reverse: function() { + reverse: function () { return RepeatForever.create(this.other.reverse()); }, - copy: function() { + copy: function () { return RepeatForever.create(this.other.copy()); } }); @@ -134,16 +142,177 @@ var FiniteTimeAction = Action.extend(/** @lends cocos.actions.FiniteTimeAction# * @constructs * @extends cocos.actions.Action */ - init: function() { - @super; + init: function () { + FiniteTimeAction.superclass.init.call(this); }, /** @ignore */ - reverse: function() { + reverse: function () { console.log('FiniteTimeAction.reverse() Override me'); } }); +var Speed = Action.extend(/** @lends cocos.actions.Speed# */{ + other: null, + + /** + * speed of the inner function + * @type Float + */ + speed: 1.0, + + /** + * Changes the speed of an action, making it take longer (speed>1) + * or less (speed<1) time. + * Useful to simulate 'slow motion' or 'fast forward' effect. + * @warning This action can't be Sequenceable because it is not an IntervalAction + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.Action + */ + init: function(opts) { + Speed.superclass.init.call(this, opts); + + this.other = opts.action; + this.speed = opts.speed; + }, + + startWithTarget: function(target) { + Speed.superclass.startWithTarget.call(this, target); + this.other.startWithTarget(this.target); + }, + + setSpeed: function(speed) { + this.speed = speed; + }, + + stop: function() { + this.other.stop(); + Speed.superclass.stop.call(this); + }, + + step: function(dt) { + this.other.step(dt * this.speed); + }, + + get_isDone: function() { + return this.other.get_isDone(); + }, + + copy: function() { + return Speed.create({action: this.other.copy(), speed: this.speed}); + }, + + reverse: function() { + return Speed.create({action: this.other.reverse(), speed: this.speed}); + } +}); + +var Follow = Action.extend(/** @lends cocos.actions.Follow# */{ + /** + * node to follow + */ + followedNode: null, + + /** + * whether camera should be limited to certain area + * @type {Boolean} + */ + boundarySet: false, + + /** + * if screensize is bigger than the boundary - update not needed + * @type {Boolean} + */ + boundaryFullyCovered: false, + + /** + * fast access to the screen dimensions + * @type {geometry.Point} + */ + halfScreenSize: null, + fullScreenSize: null, + + /** + * world boundaries + * @type {Float} + */ + leftBoundary: 0, + rightBoundary: 0, + topBoundary: 0, + bottomBoundary: 0, + + /** + * @class Follow an action that "follows" a node. + * + * Eg: + * layer.runAction(cocos.actions.Follow.create({target: hero})) + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.Action + * + * @opt {cocos.nodes.Node} target + * @opt {geometry.Rect} worldBoundary + */ + init: function(opts) { + Follow.superclass.init.call(this, opts); + + this.followedNode = opts.target; + + var s = require('../Director').Director.get('sharedDirector').get('winSize'); + this.fullScreenSize = geo.ccp(s.width, s.height); + this.halfScreenSize = geo.ccpMult(this.fullScreenSize, geo.ccp(0.5, 0.5)); + + if (opts.worldBoundary !== undefined) { + this.boundarySet = true; + this.leftBoundary = -((opts.worldBoundary.origin.x + opts.worldBoundary.size.width) - this.fullScreenSize.x); + this.rightBoundary = -opts.worldBoundary.origin.x; + this.topBoundary = -opts.worldBoundary.origin.y; + this.bottomBoundary = -((opts.worldBoundary.origin.y+opts.worldBoundary.size.height) - this.fullScreenSize.y); + + if (this.rightBoundary < this.leftBoundary) { + // screen width is larger than world's boundary width + //set both in the middle of the world + this.rightBoundary = this.leftBoundary = (this.leftBoundary + this.rightBoundary) / 2; + } + if (this.topBoundary < this.bottomBoundary) + { + // screen width is larger than world's boundary width + //set both in the middle of the world + this.topBoundary = this.bottomBoundary = (this.topBoundary + this.bottomBoundary) / 2; + } + if ((this.topBoundary == this.bottomBoundary) && (this.leftBoundary == this.rightBoundary)) { + this.boundaryFullyCovered = true; + } + } + }, + + step: function(dt) { + if (this.boundarySet) { + // whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased + if (this.boundaryFullyCovered) { + return; + } + var tempPos = geo.ccpSub(this.halfScreenSize, this.followedNode.get('position')); + this.target.set('position', ccp( + Math.min(Math.max(tempPos.x, this.leftBoundary), this.rightBoundary), + Math.min(Math.max(tempPos.y, this.bottomBoundary), this.topBoundary)) + ); + } else { + this.target.set('position', geo.ccpSub(this.halfScreenSize, this.followedNode.get('position'))); + } + }, + + get_isDone: function() { + return !this.followedNode.get('isRunning'); + } +}); + + exports.Action = Action; exports.RepeatForever = RepeatForever; exports.FiniteTimeAction = FiniteTimeAction; +exports.Speed = Speed; +exports.Follow = Follow; diff --git a/src/libs/cocos2d/actions/ActionEase.js b/src/libs/cocos2d/actions/ActionEase.js new file mode 100644 index 0000000..87b8cc0 --- /dev/null +++ b/src/libs/cocos2d/actions/ActionEase.js @@ -0,0 +1,542 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + ActionInterval = require('./ActionInterval').ActionInterval, + geo = require('geometry'), + ccp = geo.ccp; + +var ActionEase = ActionInterval.extend(/** @lends cocos.actions.ActionEase# */{ + other: null, + + /** + * @class Base class for Easing actions + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionEase + * + * @opt {cocos.actions.ActionInterval} action + */ + init: function(opts) { + if (!opts.action) { + throw "Ease: action argument must be non-nil"; + } + ActionEase.superclass.init.call(this, {duration: opts.action.duration}); + + this.other = opts.action; + }, + + startWithTarget: function(target) { + ActionEase.superclass.startWithTarget.call(this, target); + this.other.startWithTarget(this.target); + }, + + stop: function() { + this.other.stop(); + ActionEase.superclass.stop.call(this); + }, + /* + update: function(t) { + this.other.update(t); + }, + */ + copy: function() { + return ActionEase.create({action: this.other.copy()}); + }, + + reverse: function() { + return ActionEase.create({action: this.other.reverse()}); + } +}); + +var EaseRate = ActionEase.extend(/** @lends cocos.actions.EaseRate# */{ + /** + * rate value for the actions + * @type {Float} + */ + rate: 0, + + /** + * @class EaseRate Base class for Easing actions with rate parameter + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionEase + * + * @opt {cocos.actions.ActionInterval} action + * @opt {Float} rate + */ + init: function(opts) { + EaseRate.superclass.init.call(this, opts); + + this.rate = opts.rate; + }, + + copy: function() { + return EaseRate.create({action: this.other.copy(), rate: this.rate}); + }, + + reverse: function() { + return EaseRate.create({action: this.other.reverse(), rate: 1 / this.rate}); + } +}); + +var EaseIn = EaseRate.extend(/** @lends cocos.actions.EaseIn# */{ + /** + * @class EaseIn EaseIn action with a rate + */ + update: function(t) { + this.other.update(Math.pow(t, this.rate)); + }, + + copy: function() { + return EaseIn.create({action: this.other.copy(), rate: this.rate}); + }, + + reverse: function() { + return EaseIn.create({action: this.other.reverse(), rate: 1 / this.rate}); + } +}); + +var EaseOut = EaseRate.extend(/** @lends cocos.actions.EaseOut# */{ + /** + * @class EaseOut EaseOut action with a rate + */ + update: function(t) { + this.other.update(Math.pow(t, 1/this.rate)); + }, + + copy: function() { + return EaseOut.create({action: this.other.copy(), rate: this.rate}); + }, + + reverse: function() { + return EaseOut.create({action: this.other.reverse(), rate: 1 / this.rate}); + } +}); + +var EaseInOut = EaseRate.extend(/** @lends cocos.actions.EaseInOut# */{ + /** + * @class EaseInOut EaseInOut action with a rate + */ + update: function(t) { + var sign = 1; + var r = Math.floor(this.rate); + if (r % 2 == 0) { + sign = -1; + } + t *= 2; + if (t < 1) { + this.other.update(0.5 * Math.pow(t, this.rate)); + } else { + this.other.update(sign * 0.5 * (Math.pow(t-2, this.rate) + sign * 2)); + } + }, + + copy: function() { + return EaseInOut.create({action: this.other.copy(), rate: this.rate}); + }, + + reverse: function() { + return EaseInOut.create({action: this.other.reverse(), rate: this.rate}); + } +}); + +var EaseExponentialIn = ActionEase.extend(/** @lends cocos.actions.EaseExponentialIn# */{ + /** + * @class EaseExponentialIn EaseExponentialIn action + */ + update: function(t) { + this.other.update((t == 0) ? 0 : (Math.pow(2, 10 * (t/1 - 1)) - 1 * 0.001)); + }, + + copy: function() { + return EaseExponentialIn.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseExponentialOut.create({action: this.other.reverse()}); + } +}); + +var EaseExponentialOut = ActionEase.extend(/** @lends cocos.actions.EaseExponentialOut# */{ + /** + * @class EaseExponentialOut EaseExponentialOut action + */ + update: function(t) { + this.other.update((t == 1) ? 1 : (-Math.pow(2, -10 * t/1) + 1)); + }, + + copy: function() { + return EaseExponentialOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseExponentialIn.create({action: this.other.reverse()}); + } +}); + +var EaseExponentialInOut = ActionEase.extend(/** @lends cocos.actions.EaseExponentialInOut# */{ + /** + * @class EaseExponentialInOut EaseExponentialInOut action + */ + update: function(t) { + t /= 0.5; + if (t < 1) { + t = 0.5 * Math.pow(2, 10 * (t - 1)); + } else { + t = 0.5 * (-Math.pow(2, -10 * (t - 1)) + 2); + } + this.other.update(t); + }, + + copy: function() { + return EaseExponentialInOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return EaseExponentialInOut.create({action: this.other.reverse()}); + } +}); + +var EaseSineIn = ActionEase.extend(/** @lends cocos.actions.EaseSineIn# */{ + /** + * @class EaseSineIn EaseSineIn action + */ + update: function(t) { + this.other.update(-1 * Math.cos(t * Math.PI_2) + 1); + }, + + copy: function() { + return EaseSineIn.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseSineOut.create({action: this.other.reverse()}); + } +}); + +var EaseSineOut = ActionEase.extend(/** @lends cocos.actions.EaseSineOut# */{ + /** + * @class EaseSineOut EaseSineOut action + */ + update: function(t) { + this.other.update(Math.sin(t * Math.PI_2)); + }, + + copy: function() { + return EaseSineOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseSineIn.create({action: this.other.reverse()}); + } +}); + +var EaseSineInOut = ActionEase.extend(/** @lends cocos.actions.EaseSineInOut# */{ + /** + * @class EaseSineInOut EaseSineInOut action + */ + update: function(t) { + this.other.update(-0.5 * (Math.cos(t * Math.PI) - 1)); + }, + + copy: function() { + return EaseSineInOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return EaseSineInOut.create({action: this.other.reverse()}); + } +}); + +var EaseElastic = ActionEase.extend(/** @lends cocos.actions.EaseElastic# */{ + /** + * period of the wave in radians. default is 0.3 + * @type {Float} + */ + period: 0.3, + + /** + * @class EaseElastic Ease Elastic abstract class + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionEase + * + * @opt {cocos.actions.ActionInterval} action + * @opt {Float} period + */ + init: function(opts) { + EaseElastic.superclass.init.call(this, {action: opts.action}); + + if (opts.period !== undefined) { + this.period = opts.period; + } + }, + + copy: function() { + return EaseElastic.create({action: this.other.copy(), period: this.period}); + }, + + reverse: function() { + window.console.warn("EaseElastic reverse(): Override me"); + return null; + } +}); + +var EaseElasticIn = EaseElastic.extend(/** @lends cocos.actions.EaseElasticIn# */{ + /** + * @class EaseElasticIn Ease Elastic In action + */ + update: function(t) { + var newT = 0; + if (t == 0 || t == 1) { + newT = t; + } else { + var s = this.period / 4; + t -= 1; + newT = -Math.pow(2, 10 * t) * Math.sin((t - s) * Math.PI*2 / this.period); + } + this.other.update(newT); + }, + + // Wish we could use base class's copy + copy: function() { + return EaseElasticIn.create({action: this.other.copy(), period: this.period}); + }, + + reverse: function() { + return exports.EaseElasticOut.create({action: this.other.reverse(), period: this.period}); + } +}); + +var EaseElasticOut = EaseElastic.extend(/** @lends cocos.actions.EaseElasticOut# */{ + /** + * @class EaseElasticOut Ease Elastic Out action + */ + update: function(t) { + var newT = 0; + if (t == 0 || t == 1) { + newT = t; + } else { + var s = this.period / 4; + newT = Math.pow(2, -10 * t) * Math.sin((t - s) * Math.PI*2 / this.period) + 1; + } + this.other.update(newT); + }, + + copy: function() { + return EaseElasticOut.create({action: this.other.copy(), period: this.period}); + }, + + reverse: function() { + return exports.EaseElasticIn.create({action: this.other.reverse(), period: this.period}); + } +}); + +var EaseElasticInOut = EaseElastic.extend(/** @lends cocos.actions.EaseElasticInOut# */{ + /** + * @class EaseElasticInOut Ease Elastic InOut action + */ + update: function(t) { + var newT = 0; + if (t == 0 || t == 1) { + newT = t; + } else { + t *= 2; + if (this.period == 0) { + this.period = 0.3 * 1.5; + } + var s = this.period / 4; + + t -= 1; + if (t < 0) { + newT = -0.5 * Math.pow(2, 10 * t) * Math.sin((t - s) * Math.PI*2 / this.period); + } else { + newT = Math.pow(2, -10 * t) * Math.sin((t - s) * Math.PI*2 / this.period) * 0.5 + 1; + } + } + this.other.update(newT); + }, + + copy: function() { + return EaseElasticInOut.create({action: this.other.copy(), period: this.period}); + }, + + reverse: function() { + return EaseElasticInOut.create({action: this.other.reverse(), period: this.period}); + } +}); + +var EaseBounce = ActionEase.extend(/** @lends cocos.actions.EaseBounce# */{ + /** + * @class EaseBounce abstract class + */ + bounceTime: function(t) { + // Direct cut & paste from CCActionEase.m, obviously. + // Glad someone else figured out all this math... + if (t < 1 / 2.75) { + return 7.5625 * t * t; + } + else if (t < 2 / 2.75) { + t -= 1.5 / 2.75; + return 7.5625 * t * t + 0.75; + } + else if (t < 2.5 / 2.75) { + t -= 2.25 / 2.75; + return 7.5625 * t * t + 0.9375; + } + + t -= 2.625 / 2.75; + return 7.5625 * t * t + 0.984375; + } +}); + +var EaseBounceIn = EaseBounce.extend(/** @lends cocos.actions.EaseBounceIn# */{ + /** + * @class EaseBounceIn EaseBounceIn action + */ + update: function(t) { + var newT = 1 - this.bounceTime(1-t); + this.other.update(newT); + }, + + copy: function() { + return EaseBounceIn.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseBounceOut.create({action: this.other.reverse()}); + } +}); + +var EaseBounceOut = EaseBounce.extend(/** @lends cocos.actions.EaseBounceOut# */{ + /** + * @class EaseBounceOut EaseBounceOut action + */ + update: function(t) { + var newT = this.bounceTime(t); + this.other.update(newT); + }, + + copy: function() { + return EaseBounceOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseBounceIn.create({action: this.other.reverse()}); + } +}); + +var EaseBounceInOut = EaseBounce.extend(/** @lends cocos.actions.EaseBounceInOut# */{ + /** + * @class EaseBounceInOut EaseBounceInOut action + */ + update: function(t) { + var newT = 0; + if (t < 0.5) { + t *= 2; + newT = (1 - this.bounceTime(1 - t)) * 0.5; + } else { + newT = this.bounceTime(t * 2 - 1) * 0.5 + 0.5; + } + this.other.update(newT); + }, + + copy: function() { + return EaseBounceInOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return EaseBounceInOut.create({action: this.other.reverse()}); + } +}); + +var EaseBackIn = ActionEase.extend(/** @lends cocos.actions.EaseBackIn# */{ + /** + * @class EaseBackIn EaseBackIn action + */ + update: function(t) { + var overshoot = 1.70158; + this.other.update(t * t * ((overshoot + 1) * t - overshoot)); + }, + + copy: function() { + return EaseBackIn.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseBackOut.create({action: this.other.reverse()}); + } +}); + +var EaseBackOut = ActionEase.extend(/** @lends cocos.actions.EaseBackOut# */{ + /** + * @class EaseBackOut EaseBackOut action + */ + update: function(t) { + var overshoot = 1.70158; + t -= 1; + this.other.update(t * t * ((overshoot + 1) * t + overshoot) + 1); + }, + + copy: function() { + return EaseBackOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return exports.EaseBackIn.create({action: this.other.reverse()}); + } +}); + +var EaseBackInOut = ActionEase.extend(/** @lends cocos.actions.EaseBackInOut# */{ + /** + * @class EaseBackInOut EaseBackInOut action + */ + update: function(t) { + // Where do these constants come from? + var overshoot = 1.70158 * 1.525; + t *= 2; + if (t < 1) { + this.other.update((t * t * ((overshoot + 1) * t - overshoot)) / 2); + } else { + t -= 2; + this.other.update((t * t * ((overshoot + 1) * t + overshoot)) / 2 + 1); + } + }, + + copy: function() { + return EaseBackInOut.create({action: this.other.copy()}); + }, + + reverse: function() { + return EaseBackInOut.create({action: this.other.reverse()}); + } +}); + +exports.ActionEase = ActionEase; +exports.EaseRate = EaseRate; +exports.EaseIn = EaseIn; +exports.EaseOut = EaseOut; +exports.EaseInOut = EaseInOut; +exports.EaseExponentialIn = EaseExponentialIn; +exports.EaseExponentialOut = EaseExponentialOut; +exports.EaseExponentialInOut = EaseExponentialInOut; +exports.EaseSineIn = EaseSineIn; +exports.EaseSineOut = EaseSineOut; +exports.EaseSineInOut = EaseSineInOut; +exports.EaseElastic = EaseElastic; +exports.EaseElasticIn = EaseElasticIn; +exports.EaseElasticOut = EaseElasticOut; +exports.EaseElasticInOut = EaseElasticInOut; +exports.EaseBounce = EaseBounce; +exports.EaseBounceIn = EaseBounceIn; +exports.EaseBounceOut = EaseBounceOut; +exports.EaseBounceInOut = EaseBounceInOut; +exports.EaseBackIn = EaseBackIn; +exports.EaseBackOut = EaseBackOut; +exports.EaseBackInOut = EaseBackInOut; + diff --git a/src/libs/cocos2d/actions/ActionInstant.js b/src/libs/cocos2d/actions/ActionInstant.js index 5860f55..0fb642a 100644 --- a/src/libs/cocos2d/actions/ActionInstant.js +++ b/src/libs/cocos2d/actions/ActionInstant.js @@ -1,58 +1,126 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), act = require('./Action'), ccp = require('geometry').ccp; var ActionInstant = act.FiniteTimeAction.extend(/** @lends cocos.actions.ActionInstant */{ /** - * Base class for actions that triggers instantly. They have no duration. + * @class Base class for actions that triggers instantly. They have no duration. * * @memberOf cocos.actions - * @constructs * @extends cocos.actions.FiniteTimeAction + * @constructs */ - init: function(opts) { - @super; + init: function (opts) { + ActionInstant.superclass.init.call(this, opts); + this.duration = 0; }, - get_isDone: function() { + + get_isDone: function () { return true; }, - step: function(dt) { + + step: function (dt) { this.update(1); }, - update: function(t) { + + update: function (t) { // ignore }, - reverse: function() { + + copy: function() { + return this; + }, + + reverse: function () { return this.copy(); } }); +var Show = ActionInstant.extend(/** @lends cocos.actions.Show# */{ + /** + * @class Show Show the node + **/ + startWithTarget: function(target) { + Show.superclass.startWithTarget.call(this, target); + this.target.set('visible', true); + }, + + copy: function() { + return Show.create(); + }, + + reverse: function() { + return exports.Hide.create(); + } +}); + +var Hide = ActionInstant.extend(/** @lends cocos.actions.Hide# */{ + /** + * @class Hide Hide the node + **/ + startWithTarget: function(target) { + Show.superclass.startWithTarget.call(this, target); + this.target.set('visible', false); + }, + + copy: function() { + return Hide.create(); + }, + + reverse: function() { + return exports.Show.create(); + } +}); + +var ToggleVisibility = ActionInstant.extend(/** @lends cocos.actions.ToggleVisibility# */{ + /** + * @class ToggleVisibility Toggles the visibility of a node + **/ + startWithTarget: function(target) { + ToggleVisibility.superclass.startWithTarget.call(this, target); + var vis = this.target.get('visible'); + this.target.set('visible', !vis); + }, + + copy: function() { + return ToggleVisibility.create(); + } +}); + var FlipX = ActionInstant.extend(/** @lends cocos.actions.FlipX# */{ flipX: false, /** - * Flips a sprite horizontally + * @class FlipX Flips a sprite horizontally * * @memberOf cocos.actions - * @constructs * @extends cocos.actions.ActionInstant + * @constructs * * @opt {Boolean} flipX Should the sprite be flipped */ - init: function(opts) { - @super; + init: function (opts) { + FlipX.superclass.init.call(this, opts); - this.flipX = opts['flipX']; + this.flipX = opts.flipX; }, - startWithTarget: function(target) { - @super; + + startWithTarget: function (target) { + FlipX.superclass.startWithTarget.call(this, target); + target.set('flipX', this.flipX); }, - reverse: function() { + + reverse: function () { return FlipX.create({flipX: !this.flipX}); }, - copy: function() { + + copy: function () { return FlipX.create({flipX: this.flipX}); } }); @@ -61,31 +129,107 @@ var FlipY = ActionInstant.extend(/** @lends cocos.actions.FlipY# */{ flipY: false, /** - * Flips a sprite vertically + * @class FlipY Flips a sprite vertically * * @memberOf cocos.actions - * @constructs * @extends cocos.actions.ActionInstant + * @constructs * * @opt {Boolean} flipY Should the sprite be flipped */ - init: function(opts) { - @super; + init: function (opts) { + FlipY.superclass.init.call(this, opts); - this.flipY = opts['flipY']; + this.flipY = opts.flipY; }, - startWithTarget: function(target) { - @super; + + startWithTarget: function (target) { + FlipY.superclass.startWithTarget.call(this, target); + target.set('flipY', this.flipY); }, - reverse: function() { + + reverse: function () { return FlipY.create({flipY: !this.flipY}); }, - copy: function() { + + copy: function () { return FlipY.create({flipY: this.flipY}); } }); +var Place = ActionInstant.extend(/** @lends cocos.actions.Place# */{ + position: null, + + /** + * @class Place Places the node in a certain position + * + * @memberOf cocos.actions + * @extends cocos.actions.ActionInstant + * @constructs + * + * @opt {geometry.Point} position + */ + init: function(opts) { + Place.superclass.init.call(this, opts); + this.set('position', util.copy(opts.position)); + }, + + startWithTarget: function(target) { + Place.superclass.startWithTarget.call(this, target); + this.target.set('position', this.position); + }, + + copy: function() { + return Place.create({position: this.position}); + } +}); + +var CallFunc = ActionInstant.extend(/** @lends cocos.actions.CallFunc# */{ + callback: null, + target: null, + method: null, + + /** + * @class CallFunc Calls a 'callback' + * + * @memberOf cocos.actions + * @extends cocos.actions.ActionInstant + * @constructs + * + * @opt {BObject} target + * @opt {String|Function} method + */ + init: function(opts) { + CallFunc.superclass.init.call(this, opts); + + // Save target & method so that copy() can recreate callback + this.target = opts.target; + this.method = opts.method; + this.callback = util.callback(this.target, this.method); + }, + + startWithTarget: function(target) { + CallFunc.superclass.startWithTarget.call(this, target); + this.execute(target); + }, + + execute: function(target) { + // Pass target to callback + this.callback.call(this, target); + }, + + copy: function() { + return CallFunc.create({target: this.target, method: this.method}); + } +}); + exports.ActionInstant = ActionInstant; +exports.Show = Show; +exports.Hide = Hide; +exports.ToggleVisibility = ToggleVisibility; exports.FlipX = FlipX; exports.FlipY = FlipY; +exports.Place = Place; +exports.CallFunc = CallFunc; + diff --git a/src/libs/cocos2d/actions/ActionInterval.js b/src/libs/cocos2d/actions/ActionInterval.js index 59b352b..7be4b2a 100644 --- a/src/libs/cocos2d/actions/ActionInterval.js +++ b/src/libs/cocos2d/actions/ActionInterval.js @@ -1,6 +1,12 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), act = require('./Action'), - ccp = require('geometry').ccp; + geo = require('geometry'), + ccp = geo.ccp; + var ActionInterval = act.FiniteTimeAction.extend(/** @lends cocos.actions.ActionInterval# */{ /** @@ -12,7 +18,7 @@ var ActionInterval = act.FiniteTimeAction.extend(/** @lends cocos.actions.Action _firstTick: true, /** - * Base class actions that do have a finite time duration. + * Base class actions that do have a finite time duration. * * Possible actions: * @@ -25,11 +31,11 @@ var ActionInterval = act.FiniteTimeAction.extend(/** @lends cocos.actions.Action * * @opt {Float} duration Number of seconds to run action for */ - init: function(opts) { - @super; + init: function (opts) { + ActionInterval.superclass.init.call(this, opts); - var dur = opts['duration'] || 0; - if (dur == 0) { + var dur = opts.duration || 0; + if (dur === 0) { dur = 0.0000001; } @@ -38,11 +44,11 @@ var ActionInterval = act.FiniteTimeAction.extend(/** @lends cocos.actions.Action this._firstTick = true; }, - get_isDone: function() { + get_isDone: function () { return (this.elapsed >= this.duration); }, - step: function(dt) { + step: function (dt) { if (this._firstTick) { this._firstTick = false; this.elapsed = 0; @@ -50,21 +56,49 @@ var ActionInterval = act.FiniteTimeAction.extend(/** @lends cocos.actions.Action this.elapsed += dt; } - this.update(Math.min(1, this.elapsed/this.duration)); + this.update(Math.min(1, this.elapsed / this.duration)); }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + ActionInterval.superclass.startWithTarget.call(this, target); this.elapsed = 0.0; this._firstTick = true; }, - reverse: function() { - throw "Reverse Action not implemented" + copy: function() { + throw "copy() not implemented"; + }, + + reverse: function () { + throw "Reverse Action not implemented"; + } +}); + +var DelayTime = ActionInterval.extend(/** @lends cocos.actions.DelayTime# */{ + /** + * @class DelayTime Delays the action a certain amount of seconds + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionInterval + */ + update: function (t) { + if (t === 1.0) { + this.stop(); + } + }, + + copy: function () { + return DelayTime.create({duration: this.get('duration')}); + }, + + reverse: function () { + return DelayTime.create({duration: this.get('duration')}); } }); + var ScaleTo = ActionInterval.extend(/** @lends cocos.actions.ScaleTo# */{ /** * Current X Scale @@ -117,7 +151,7 @@ var ScaleTo = ActionInterval.extend(/** @lends cocos.actions.ScaleTo# */{ deltaY: 0.0, /** - * Scales a cocos.Node object to a zoom factor by modifying it's scale attribute. + * @class ScaleTo Scales a cocos.Node object to a zoom factor by modifying it's scale attribute. * * @memberOf cocos.actions * @constructs @@ -128,21 +162,21 @@ var ScaleTo = ActionInterval.extend(/** @lends cocos.actions.ScaleTo# */{ * @opt {Float} [scaleX] Size to scale width of Node to * @opt {Float} [scaleY] Size to scale height of Node to */ - init: function(opts) { - @super; + init: function (opts) { + ScaleTo.superclass.init.call(this, opts); - if (opts['scale'] != undefined) { - this.endScaleX = this.endScaleY = opts['scale']; + if (opts.scale !== undefined) { + this.endScaleX = this.endScaleY = opts.scale; } else { - this.endScaleX = opts['scaleX']; - this.endScaleY = opts['scaleY']; + this.endScaleX = opts.scaleX; + this.endScaleY = opts.scaleY; } }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + ScaleTo.superclass.startWithTarget.call(this, target); this.startScaleX = this.target.get('scaleX'); this.startScaleY = this.target.get('scaleY'); @@ -150,19 +184,25 @@ var ScaleTo = ActionInterval.extend(/** @lends cocos.actions.ScaleTo# */{ this.deltaY = this.endScaleY - this.startScaleY; }, - update: function(t) { + update: function (t) { if (!this.target) { return; } - + this.target.set('scaleX', this.startScaleX + this.deltaX * t); this.target.set('scaleY', this.startScaleY + this.deltaY * t); + }, + + copy: function () { + return ScaleTo.create({duration: this.get('duration'), + scaleX: this.get('endScaleX'), + scaleY: this.get('endScaleY')}); } }); var ScaleBy = ScaleTo.extend(/** @lends cocos.actions.ScaleBy# */{ /** - * Scales a cocos.Node object to a zoom factor by modifying it's scale attribute. + * @class ScaleBy Scales a cocos.Node object to a zoom factor by modifying it's scale attribute. * * @memberOf cocos.actions * @constructs @@ -173,19 +213,19 @@ var ScaleBy = ScaleTo.extend(/** @lends cocos.actions.ScaleBy# */{ * @opt {Float} [scaleX] Size to scale width of Node by * @opt {Float} [scaleY] Size to scale height of Node by */ - init: function() { - @super; + init: function (opts) { + ScaleBy.superclass.init.call(this, opts); }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + ScaleBy.superclass.startWithTarget.call(this, target); this.deltaX = this.startScaleX * this.endScaleX - this.startScaleX; this.deltaY = this.startScaleY * this.endScaleY - this.startScaleY; }, - reverse: function() { - return ScaleBy.create({duration: this.duration, scaleX:1/this.endScaleX, scaleY:1/this.endScaleY}); + reverse: function () { + return ScaleBy.create({duration: this.get('duration'), scaleX: 1 / this.endScaleX, scaleY: 1 / this.endScaleY}); } }); @@ -210,9 +250,9 @@ var RotateTo = ActionInterval.extend(/** @lends cocos.actions.RotateTo# */{ diffAngle: 0, /** - * Rotates a cocos.Node object to a certain angle by modifying its rotation + * @class RotateTo Rotates a cocos.Node object to a certain angle by modifying its rotation * attribute. The direction will be decided by the shortest angle. - * + * * @memberOf cocos.actions * @constructs * @extends cocos.actions.ActionInterval @@ -220,14 +260,14 @@ var RotateTo = ActionInterval.extend(/** @lends cocos.actions.RotateTo# */{ * @opt {Float} duration Number of seconds to run action for * @opt {Float} angle Angle in degrees to rotate to */ - init: function(opts) { - @super; + init: function (opts) { + RotateTo.superclass.init.call(this, opts); - this.dstAngle = opts['angle']; + this.dstAngle = opts.angle; }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + RotateTo.superclass.startWithTarget.call(this, target); this.startAngle = target.get('rotation'); @@ -245,8 +285,12 @@ var RotateTo = ActionInterval.extend(/** @lends cocos.actions.RotateTo# */{ } }, - update: function(t) { + update: function (t) { this.target.set('rotation', this.startAngle + this.diffAngle * t); + }, + + copy: function () { + return RotateTo.create({duration: this.get('duration'), angle: this.get('dstAngle')}); } }); @@ -258,7 +302,7 @@ var RotateBy = RotateTo.extend(/** @lends cocos.actions.RotateBy# */{ angle: 0, /** - * Rotates a cocos.Node object to a certain angle by modifying its rotation + * @class RotateBy Rotates a cocos.Node object to a certain angle by modifying its rotation * attribute. The direction will be decided by the shortest angle. * * @memberOf cocos.action @@ -268,117 +312,712 @@ var RotateBy = RotateTo.extend(/** @lends cocos.actions.RotateBy# */{ * @opt {Float} duration Number of seconds to run action for * @opt {Float} angle Angle in degrees to rotate by */ - init: function(opts) { - @super; + init: function (opts) { + RotateBy.superclass.init.call(this, opts); - this.angle = opts['angle']; + this.angle = opts.angle; }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + RotateBy.superclass.startWithTarget.call(this, target); this.startAngle = this.target.get('rotation'); }, - update: function(t) { - this.target.set('rotation', this.startAngle + this.angle *t); + update: function (t) { + this.target.set('rotation', this.startAngle + this.angle * t); }, - reverse: function() { - return RotateBy.create({duration: this.duration, angle: -this.angle}); + copy: function () { + return RotateBy.create({duration: this.get('duration'), angle: this.angle}); }, + + reverse: function () { + return RotateBy.create({duration: this.get('duration'), angle: -this.angle}); + } +}); + +var MoveTo = ActionInterval.extend(/** @lends cocos.actions.MoveTo# */{ + delta: null, + startPosition: null, + endPosition: null, + + /** + * @class MoveTo Animates moving a cocos.nodes.Node object to a another point. + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionInterval + * + * @opt {Float} duration Number of seconds to run action for + * @opt {geometry.Point} position Destination position + */ + init: function (opts) { + MoveTo.superclass.init.call(this, opts); + this.set('endPosition', util.copy(opts.position)); + }, + + startWithTarget: function (target) { + MoveTo.superclass.startWithTarget.call(this, target); + + this.set('startPosition', util.copy(target.get('position'))); + this.set('delta', geo.ccpSub(this.get('endPosition'), this.get('startPosition'))); + }, + + update: function (t) { + var startPosition = this.get('startPosition'), + delta = this.get('delta'); + this.target.set('position', ccp(startPosition.x + delta.x * t, startPosition.y + delta.y * t)); + }, + copy: function() { - return RotateBy.create({duration: this.duration, angle: this.angle}); + return MoveTo.create({duration: this.get('duration'), position: this.get('endPosition')}); } }); +var MoveBy = MoveTo.extend(/** @lends cocos.actions.MoveBy# */{ + /** + * @class MoveBy Animates moving a cocos.node.Node object by a given number of pixels + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.MoveTo + * + * @opt {Float} duration Number of seconds to run action for + * @opt {geometry.Point} position Number of pixels to move by + */ + init: function (opts) { + MoveBy.superclass.init.call(this, opts); + this.set('delta', util.copy(opts.position)); + }, -var Sequence = ActionInterval.extend(/** @lends cocos.actions.Sequence# */{ + startWithTarget: function (target) { + var dTmp = this.get('delta'); + MoveBy.superclass.startWithTarget.call(this, target); + this.set('delta', dTmp); + }, + + copy: function() { + return MoveBy.create({duration: this.get('duration'), position: this.get('delta')}); + }, + + reverse: function() { + var delta = this.get('delta'); + return MoveBy.create({duration: this.get('duration'), position: geo.ccp(-delta.x, -delta.y)}); + } +}); + +var JumpBy = ActionInterval.extend(/** @lends cocos.actions.JumpBy# */{ /** - * Array of actions to run - * @type cocos.Node[] + * Number of pixels to jump by + * @type geometry.Point */ - actions: null, - + delta: null, + + /** + * Height of jump + * @type Float + */ + height: 0, + /** - * The array index of the currently running action + * Number of times to jump * @type Integer */ - currentActionIndex: 0, - + jumps: 0, + /** - * The duration when the current action finishes - * @type Float + * Starting point + * @type geometry.Point */ - currentActionEndDuration: 0, - + startPosition: null, + /** - * Runs a number of actions sequentially, one after another + * @class JumpBy Moves a CCNode object simulating a parabolic jump movement by modifying it's position attribute. * * @memberOf cocos.actions * @constructs * @extends cocos.actions.ActionInterval * * @opt {Float} duration Number of seconds to run action for - * @opt {cocos.actions.Action[]} Array of actions to run in sequence + * @opt {geometry.Point} startPosition Point at which jump starts + * @opt {geometry.Point} delta Number of pixels to jump by + * @opt {Float} height Height of jump + * @opt {Int} jumps Number of times to repeat */ init: function(opts) { - @super; + JumpBy.superclass.init.call(this, opts); + + this.delta = util.copy(opts.delta); + this.height = opts.height; + this.jumps = opts.jumps; + }, + + copy: function() { + return JumpBy.create({duration: this.duration, + delta: this.delta, + height: this.height, + jumps: this.jumps}); + }, + + startWithTarget: function(target) { + JumpBy.superclass.startWithTarget.call(this, target); + this.set('startPosition', target.get('position')); + }, + + update: function(t) { + // parabolic jump + var frac = (t * this.jumps) % 1.0; + var y = this.height * 4 * frac * (1 - frac); + y += this.delta.y * t; + var x = this.delta.x * t; + this.target.set('position', geo.ccp(this.startPosition.x + x, this.startPosition.y + y)); + }, + + reverse: function() { + return JumpBy.create({duration: this.duration, + delta: geo.ccp(-this.delta.x, -this.delta.y), + height: this.height, + jumps: this.jumps}); + } +}); - this.actions = util.copy(opts['actions']); - this.actionSequence = {}; +var JumpTo = JumpBy.extend(/** @lends cocos.actions.JumpTo# */{ + /** + * @class JumpTo Moves a Node object to a parabolic position simulating a jump + * movement by modifying it's position attribute. + * + * @memberOf cocos.actions + * @extends cocos.actions.JumpBy + */ + startWithTarget: function(target) { + JumpTo.superclass.startWithTarget.call(this, target); + this.delta = geo.ccp(this.delta.x - this.startPosition.x, this.delta.y - this.startPosition.y); + } +}); + +var BezierBy = ActionInterval.extend(/** @lends cocos.actions.BezierBy# */{ + /** + * @type {geometry.BezierConfig} + */ + config: null, + + startPosition: null, + + /** + * @class BezierBy An action that moves the target with a cubic Bezier curve by a certain distance. + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionInterval + * + * @opts {geometry.BezierConfig} bezier Bezier control points object + * @opts {Float} duration + */ + init: function(opts) { + BezierBy.superclass.init.call(this, opts); + + this.config = util.copy(opts.bezier); + }, + + startWithTarget: function(target) { + BezierBy.superclass.startWithTarget.call(this, target); + this.set('startPosition', this.target.get('position')); + }, + + update: function(t) { + var c = this.get('config'); + var xa = 0, + xb = c.controlPoint1.x, + xc = c.controlPoint2.x, + xd = c.endPosition.x, + ya = 0, + yb = c.controlPoint1.y, + yc = c.controlPoint2.y, + yd = c.endPosition.y; - util.each(this.actions, util.callback(this, function(action) { - this.duration += action.duration; - })); + var x = BezierBy.bezierat(xa, xb, xc, xd, t); + var y = BezierBy.bezierat(ya, yb, yc, yd, t); + + this.target.set('position', geo.ccpAdd(this.get('startPosition'), geo.ccp(x, y))); }, + + copy: function() { + return BezierBy.create({bezier: this.get('config'), duration: this.get('duration')}); + }, + + reverse: function() { + var c = this.get('config'), + bc = new geo.BezierConfig(); + + bc.endPosition = geo.ccpNeg(c.endPosition); + bc.controlPoint1 = geo.ccpAdd(c.controlPoint2, geo.ccpNeg(c.endPosition)); + bc.controlPoint2 = geo.ccpAdd(c.controlPoint1, geo.ccpNeg(c.endPosition)); + + return BezierBy.create({bezier: bc, duration: this.get('duration')}); + } +}); +util.extend(BezierBy, { + /** + * Bezier cubic formula + * ((1 - t) + t)3 = 1 + */ + bezierat: function(a, b, c, d, t) { + return Math.pow(1-t, 3) * a + + 3 * t * Math.pow(1-t, 2) * b + + 3 * Math.pow(t, 2) * (1 - t) * c + + Math.pow(t, 3) * d; + } +}); + +var BezierTo = BezierBy.extend(/** @lends cocos.actions.BezierTo# */{ + /** + * @class BezierTo An action that moves the target with a cubic Bezier curve to a destination point. + * + * @memberOf cocos.actions + * @extends cocos.actions.BezierBy + */ startWithTarget: function(target) { - @super; - this.currentActionIndex = 0; - this.currentActionEndDuration = this.actions[0].get('duration'); - this.actions[0].startWithTarget(this.target); + BezierTo.superclass.startWithTarget.call(this, target); + + var c = this.get('config'); + c.controlPoint1 = geo.ccpSub(c.controlPoint1, this.get('startPosition')); + c.controlPoint2 = geo.ccpSub(c.controlPoint2, this.get('startPosition')); + c.endPosition = geo.ccpSub(c.endPosition, this.get('startPosition')); + } +}); + +var Blink = ActionInterval.extend(/** @lends cocos.actions.Blink# */{ + /** + * @type {Integer} + */ + times: 1, + + /** + * @class Blink Blinks a Node object by modifying it's visible attribute + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionInterval + * + * @opts {Integer} blinks Number of times to blink + * @opts {Float} duration + */ + init: function(opts) { + Blink.superclass.init.call(this, opts); + this.times = opts.blinks; + }, + + update: function(t) { + if (! this.get_isDone()) { + var slice = 1 / this.times; + var m = t % slice; + this.target.set('visible', (m > slice/2)); + } + }, + + copy: function() { + return Blink.create({duration: this.get('duration'), blinks: this.get('times')}); }, + + reverse: function() { + return this.copy(); + } +}); - stop: function() { - util.each(this.actions, function(action) { - action.stop(); - }); +var FadeOut = ActionInterval.extend(/** @lends cocos.actions.FadeOut# */{ + /** + * @class FadeOut Fades out a cocos.nodes.Node to zero opacity + * + * @memberOf cocos.actions + * @extends cocos.actions.ActionInterval + */ + update: function (t) { + var target = this.get('target'); + if (!target) return; + target.set('opacity', 255 - (255 * t)); + }, - @super; + copy: function () { + return FadeOut.create({duration: this.get('duration')}); }, + + reverse: function () { + return exports.FadeIn.create({duration: this.get('duration')}); + } +}); - step: function(dt) { - if (this._firstTick) { - this._firstTick = false; - this.elapsed = 0; + +var FadeIn = ActionInterval.extend(/** @lends cocos.actions.FadeIn# */{ + /** + * @class FadeIn Fades in a cocos.nodes.Node to 100% opacity + * + * @memberOf cocos.actions + * @extends cocos.actions.ActionInterval + */ + update: function (t) { + var target = this.get('target'); + if (!target) return; + target.set('opacity', t * 255); + }, + + copy: function () { + return FadeIn.create({duration: this.get('duration')}); + }, + + reverse: function () { + return exports.FadeOut.create({duration: this.get('duration')}); + } +}); + +var FadeTo = ActionInterval.extend(/** @lends cocos.actions.FadeTo# */{ + /** + * The final opacity + * @type Float + */ + toOpacity: null, + + /** + * The initial opacity + * @type Float + */ + fromOpacity: null, + + /** + * @class FadeTo Fades a cocos.nodes.Node to a given opacity + * + * @memberOf cocos.actions + * @constructor + * @extends cocos.actions.ActionInterval + */ + init: function (opts) { + FadeTo.superclass.init.call(this, opts); + this.set('toOpacity', opts.toOpacity); + }, + + startWithTarget: function (target) { + FadeTo.superclass.startWithTarget.call(this, target); + this.set('fromOpacity', this.target.get('opacity')); + }, + + update: function (t) { + var target = this.get('target'); + if (!target) return; + + target.set('opacity', this.fromOpacity + ( this.toOpacity - this.fromOpacity ) * t); + }, + + copy: function() { + return FadeTo.create({duration: this.get('duration'), toOpacity: this.get('toOpacity')}); + } +}); + +var Sequence = ActionInterval.extend(/** @lends cocos.actions.Sequence# */{ + /** + * Array of actions to run + * @type cocos.nodes.Node[] + */ + actions: null, + + split: 0, + last: 0, + + /** + * Runs a pair of actions sequentially, one after another + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionInterval + * + * @opt {cocos.actions.FiniteTimeAction} one 1st action to run + * @opt {cocos.actions.FiniteTimeAction} two 2nd action to run + */ + init: function (opts) { + if (!opts.one) { + throw "Sequence argument one must be non-nil"; + } + if (!opts.two) { + throw "Sequence argument two must be non-nil"; + } + this.actions = []; + + var d = opts.one.get('duration') + opts.two.get('duration'); + + Sequence.superclass.init.call(this, {duration: d}); + + this.actions[0] = opts.one; + this.actions[1] = opts.two; + }, + + startWithTarget: function (target) { + Sequence.superclass.startWithTarget.call(this, target); + this.split = this.actions[0].get('duration') / this.get('duration'); + this.last = -1; + }, + + stop: function () { + this.actions[0].stop(); + this.actions[1].stop(); + Sequence.superclass.stop.call(this); + }, + + update: function (t) { + // This is confusing but will hopefully work better in conjunction + // with modifer actions like Repeat & Spawn... + var found = 0; + var new_t = 0; + + if (t >= this.split) { + found = 1; + if (this.split == 1) { + new_t = 1; + } else { + new_t = (t - this.split) / (1 - this.split); + } } else { - this.elapsed += dt; + found = 0; + if (this.split != 0) { + new_t = t / this.split; + } else { + new_t = 1; + } + } + if (this.last == -1 && found == 1) { + this.actions[0].startWithTarget(this.target); + this.actions[0].update(1); + this.actions[0].stop(); } + if (this.last != found) { + if (this.last != -1) { + this.actions[this.last].update(1); + this.actions[this.last].stop(); + } + this.actions[found].startWithTarget(this.target); + } + this.actions[found].update(new_t); + this.last = found; + }, - this.actions[this.currentActionIndex].step(dt); - this.update(Math.min(1, this.elapsed/this.duration)); + copy: function () { + // Constructor will copy actions + return Sequence.create({actions: this.get('actions')}); }, - update: function(dt) { - // Action finished onto the next one - if (this.elapsed > this.currentActionEndDuration) { - var previousAction = this.actions[this.currentActionIndex]; - previousAction.update(1.0); - previousAction.stop(); + reverse: function() { + return Sequence.create({actions: [this.actions[1].reverse(), this.actions[0].reverse()]}); + } +}); +util.extend(Sequence, { + /** + * Override BObject.create in order to implement recursive construction + * of actions array + */ + create: function() { + // Don't copy actions array, copy the actions + var actions = arguments[0].actions; + var prev = actions[0].copy(); + + // Recursively create Sequence with pair of actions + for (var i=1; i (this.total+1)) { + this.other.update(1); + this.total += 1; + this.other.stop(); + this.other.startWithTarget(this.target); + + // If repeat is over + if (this.total == this.times) { + // set it in the original position + this.other.update(0); + } else { + // otherwise start next repeat + this.other.update(t - this.total); + } + } else { + var r = t % 1.0; + + // fix last repeat position otherwise it could be 0 + if (dt == 1) { + r = 1; + this.total += 1; + } + this.other.update(Math.min(r, 1)); + } + }, + + get_isDone: function() { + return this.total == this.times; + }, + + copy: function() { + // Constructor copies action + return Repeat.create({action: this.other, times: this.times}); + }, + + reverse: function() { + return Repeat.create({action: this.other.reverse(), times: this.times}); + } +}); - this.currentActionIndex++; +var Spawn = ActionInterval.extend(/** @lends cocos.actions.Spawn# */{ + one: null, + two: null, - if (this.currentActionIndex < this.actions.length) { - var currentAction = this.actions[this.currentActionIndex]; - currentAction.startWithTarget(this.target); + /** + * @class Spawn Executes multiple actions simultaneously + * + * @memberOf cocos.actions + * @constructs + * @extends cocos.actions.ActionInterval + * + * @opt {cocos.actions.FiniteTimeAction} one: first action to spawn + * @opt {cocos.actions.FiniteTimeAction} two: second action to spawn + */ + init: function (opts) { + var action1 = opts.one, + action2 = opts.two; + + if (!action1 || !action2) { + throw "cocos.actions.Spawn: required actions missing"; + } + var d1 = action1.get('duration'), + d2 = action2.get('duration'); + + Spawn.superclass.init.call(this, {duration: Math.max(d1, d2)}); + + this.set('one', action1); + this.set('two', action2); + + if (d1 > d2) { + this.set('two', Sequence.create({actions: [ + action2, + DelayTime.create({duration: d1-d2}) + ]})); + } else if (d1 < d2) { + this.set('one', Sequence.create({actions: [ + action1, + DelayTime.create({duration: d2-d1}) + ]})); + } + }, + + startWithTarget: function (target) { + Spawn.superclass.startWithTarget.call(this, target); + this.get('one').startWithTarget(this.target); + this.get('two').startWithTarget(this.target); + }, + + stop: function () { + this.get('one').stop(); + this.get('two').stop(); + Spawn.superclass.stop.call(this); + }, + + step: function (dt) { + if (this._firstTick) { + this._firstTick = false; + this.elapsed = 0; + } else { + this.elapsed += dt; + } + this.get('one').step(dt); + this.get('two').step(dt); + }, + + update: function (t) { + this.get('one').update(t); + this.get('two').update(t); + }, + + copy: function () { + return Spawn.create({one: this.get('one').copy(), two: this.get('two').copy()}); + }, + + reverse: function () { + return Spawn.create({one: this.get('one').reverse(), two: this.get('two').reverse()}); + } +}); - this.currentActionEndDuration += currentAction.duration; +util.extend(Spawn, { + /** + * Helper class function to create Spawn object from array of actions + * + * @opt {Array} actions: list of actions to run simultaneously + */ + initWithActions: function (opts) { + var now, prev = opts.actions.shift(); + while (opts.actions.length > 0) { + now = opts.actions.shift(); + if (now) { + prev = this.create({one: prev, two: now}); + } else { + break; } } + return prev; } }); @@ -389,7 +1028,7 @@ var Animate = ActionInterval.extend(/** @lends cocos.actions.Animate# */{ /** - * Animates a sprite given the name of an Animation + * Animates a sprite given the name of an Animation * * @memberOf cocos.actions * @constructs @@ -399,38 +1038,38 @@ var Animate = ActionInterval.extend(/** @lends cocos.actions.Animate# */{ * @opt {cocos.Animation} animation Animation to run * @opt {Boolean} [restoreOriginalFrame=true] Return to first frame when finished */ - init: function(opts) { - this.animation = opts['animation']; - this.restoreOriginalFrame = opts['restoreOriginalFrame'] !== false; - opts['duration'] = this.animation.frames.length * this.animation.delay; + init: function (opts) { + this.animation = opts.animation; + this.restoreOriginalFrame = opts.restoreOriginalFrame !== false; + opts.duration = this.animation.frames.length * this.animation.delay; - @super; + Animate.superclass.init.call(this, opts); }, - startWithTarget: function(target) { - @super; + startWithTarget: function (target) { + Animate.superclass.startWithTarget.call(this, target); if (this.restoreOriginalFrame) { this.set('origFrame', this.target.get('displayedFrame')); } }, - stop: function() { + stop: function () { if (this.target && this.restoreOriginalFrame) { var sprite = this.target; sprite.set('displayFrame', this.origFrame); } - @super; + Animate.superclass.stop.call(this); }, - update: function(t) { + update: function (t) { var frames = this.animation.get('frames'), numberOfFrames = frames.length, idx = Math.floor(t * numberOfFrames); if (idx >= numberOfFrames) { - idx = numberOfFrames -1; + idx = numberOfFrames - 1; } var sprite = this.target; @@ -439,16 +1078,29 @@ var Animate = ActionInterval.extend(/** @lends cocos.actions.Animate# */{ } }, - copy: function() { + copy: function () { return Animate.create({animation: this.animation, restoreOriginalFrame: this.restoreOriginalFrame}); } }); exports.ActionInterval = ActionInterval; +exports.DelayTime = DelayTime; exports.ScaleTo = ScaleTo; exports.ScaleBy = ScaleBy; exports.RotateTo = RotateTo; exports.RotateBy = RotateBy; +exports.MoveTo = MoveTo; +exports.MoveBy = MoveBy; +exports.JumpBy = JumpBy; +exports.JumpTo = JumpTo; +exports.BezierBy = BezierBy; +exports.BezierTo = BezierTo; +exports.Blink = Blink; +exports.FadeIn = FadeIn; +exports.FadeOut = FadeOut; +exports.FadeTo = FadeTo; +exports.Spawn = Spawn; exports.Sequence = Sequence; +exports.Repeat = Repeat; exports.Animate = Animate; diff --git a/src/libs/cocos2d/actions/index.js b/src/libs/cocos2d/actions/index.js index 9eef9d7..a4aa606 100644 --- a/src/libs/cocos2d/actions/index.js +++ b/src/libs/cocos2d/actions/index.js @@ -1,7 +1,11 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), path = require('path'); -var modules = 'Action ActionInterval ActionInstant'.w(); +var modules = 'Action ActionInterval ActionInstant ActionEase'.w(); /** * @memberOf cocos @@ -9,7 +13,7 @@ var modules = 'Action ActionInterval ActionInstant'.w(); */ var actions = {}; -util.each(modules, function(mod, i) { +util.each(modules, function (mod, i) { util.extend(actions, require('./' + mod)); }); diff --git a/src/libs/cocos2d/config.json b/src/libs/cocos2d/config.json new file mode 100644 index 0000000..126b038 --- /dev/null +++ b/src/libs/cocos2d/config.json @@ -0,0 +1,9 @@ +{ + // Invert the Y axis so origin is at the bottom left + "FLIP_Y_AXIS": false, + + // No implemented yet + "ENABLE_WEB_GL": false, + + "SHOW_REDRAW_REGIONS": false +} diff --git a/src/libs/cocos2d/index.js b/src/libs/cocos2d/index.js index 7c2bf10..faee3a5 100644 --- a/src/libs/cocos2d/index.js +++ b/src/libs/cocos2d/index.js @@ -1,7 +1,11 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), path = require('path'); -var modules = 'SpriteFrame SpriteFrameCache Director Animation AnimationCache Scheduler ActionManager TMXXMLParser'.w() +var modules = 'Texture2D Preloader RemoteImage RemoteResource SpriteFrame SpriteFrameCache Director Animation AnimationCache Scheduler ActionManager TMXXMLParser'.w(); /** * @namespace All cocos2d objects live in this namespace @@ -11,7 +15,7 @@ var cocos = { actions: require('./actions') }; -util.each(modules, function(mod, i) { +util.each(modules, function (mod, i) { util.extend(cocos, require('./' + mod)); }); diff --git a/src/libs/cocos2d/nodes/AtlasNode.js b/src/libs/cocos2d/nodes/AtlasNode.js new file mode 100644 index 0000000..a7374ac --- /dev/null +++ b/src/libs/cocos2d/nodes/AtlasNode.js @@ -0,0 +1,77 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var SpriteBatchNode = require('./BatchNode').SpriteBatchNode, + TextureAtlas = require('../TextureAtlas').TextureAtlas, + geo = require('geometry'); + +var AtlasNode = SpriteBatchNode.extend(/** @lends cocos.AtlasNode# */{ + /** + * Characters per row + * @type Integer + */ + itemsPerRow: 0, + + /** + * Characters per column + * @type Integer + */ + itemsPerColumn: 0, + + /** + * Width of a character + * @type Integer + */ + itemWidth: 0, + + /** + * Height of a character + * @type Integer + */ + itemHeight: 0, + + + /** + * @type cocos.TextureAtlas + */ + textureAtlas: null, + + /** + * @class + * It knows how to render a TextureAtlas object. If you are going to + * render a TextureAtlas consider subclassing cocos.nodes.AtlasNode (or a + * subclass of cocos.nodes.AtlasNode) + * @memberOf cocos + * @extends cocos.nodes.SpriteBatchNode + * @constructs + * + * @opt {String} file Path to Atals image + * @opt {Integer} itemWidth Character width + * @opt {Integer} itemHeight Character height + * @opt {Integer} itemsToRender Quantity of items to render + */ + init: function (opts) { + AtlasNode.superclass.init.call(this, opts); + + this.itemWidth = opts.itemWidth; + this.itemHeight = opts.itemHeight; + + this.textureAtlas = TextureAtlas.create({file: opts.file, capacity: opts.itemsToRender}); + + + this._calculateMaxItems(); + }, + + updateAtlasValues: function () { + throw "cocos.nodes.AtlasNode:Abstract - updateAtlasValue not overriden"; + }, + + _calculateMaxItems: function () { + var s = this.textureAtlas.get('texture.contentSize'); + this.itemsPerColumn = s.height / this.itemHeight; + this.itemsPerRow = s.width / this.itemWidth; + } +}); + +exports.AtlasNode = AtlasNode; diff --git a/src/libs/cocos2d/nodes/BatchNode.js b/src/libs/cocos2d/nodes/BatchNode.js index 909152b..43d6765 100644 --- a/src/libs/cocos2d/nodes/BatchNode.js +++ b/src/libs/cocos2d/nodes/BatchNode.js @@ -1,15 +1,26 @@ +/*globals module exports resource require BObject BArray SHOW_REDRAW_REGIONS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - event = require('event'), + evt = require('events'), geo = require('geometry'), ccp = geo.ccp, TextureAtlas = require('../TextureAtlas').TextureAtlas, RenderTexture = require('./RenderTexture').RenderTexture, - Node = require('./Node').Node; + Node = require('./Node').Node; var BatchNode = Node.extend(/** @lends cocos.nodes.BatchNode# */{ + partialDraw: false, contentRect: null, renderTexture: null, dirty: true, + + /** + * Region to redraw + * @type geometry.Rect + */ + dirtyRegion: null, dynamicResize: false, /** @private @@ -28,26 +39,28 @@ var BatchNode = Node.extend(/** @lends cocos.nodes.BatchNode# */{ * @extends cocos.nodes.Node * * @opt {geometry.Size} size The size of the in-memory canvas used for drawing to + * @opt {Boolean} [partialDraw=false] Draw only the area visible on screen. Small maps may be slower in some browsers if this is true. */ - init: function(opts) { - @super; + init: function (opts) { + BatchNode.superclass.init.call(this, opts); - var size = opts['size'] || geo.sizeMake(1, 1); + var size = opts.size || geo.sizeMake(1, 1); + this.set('partialDraw', opts.partialDraw); - event.addListener(this, 'contentsize_changed', util.callback(this, this._resizeCanvas)); + evt.addListener(this, 'contentsize_changed', util.callback(this, this._resizeCanvas)); - this._dirtyRects = []; + this._dirtyRects = []; this.set('contentRect', geo.rectMake(0, 0, size.width, size.height)); this.renderTexture = RenderTexture.create(size); this.renderTexture.sprite.set('isRelativeAnchorPoint', false); this.addChild({child: this.renderTexture}); - }, + }, - addChild: function(opts) { - @super; + addChild: function (opts) { + BatchNode.superclass.addChild.call(this, opts); - var child = opts['child'], - z = opts['z']; + var child = opts.child, + z = opts.z; if (child == this.renderTexture) { return; @@ -56,36 +69,64 @@ var BatchNode = Node.extend(/** @lends cocos.nodes.BatchNode# */{ // TODO handle texture resize // Watch for changes in child - event.addListener(child, 'istransformdirty_changed', util.callback(this, function() { this.set('dirty', true); })); - event.addListener(child, 'visible_changed', util.callback(this, function() { this.set('dirty', true); })); - - this.set('dirty', true); + var watchEvents = ['position_before_changed', + 'scalex_before_changed', + 'scaley_before_changed', + 'rotation_before_changed', + 'anchorpoint_before_changed', + 'opacity_before_changed', + 'visible_before_changed']; + evt.addListener(child, watchEvents, util.callback(this, function () { + this.addDirtyRegion(child.get('boundingBox')); + })); + + this.addDirtyRegion(child.get('boundingBox')); }, - removeChild: function(opts) { - @super; + removeChild: function (opts) { + BatchNode.superclass.removeChild.call(this, opts); // TODO remove istransformdirty_changed and visible_changed listeners this.set('dirty', true); }, - _resizeCanvas: function(oldSize) { + addDirtyRegion: function (rect) { + // Increase rect slightly to compensate for subpixel artifacts + rect = util.copy(rect); + rect.origin.x -= 2; + rect.origin.y -= 2; + rect.size.width += 4; + rect.size.height += 4; + + var region = this.get('dirtyRegion'); + if (!region) { + region = rect; + } else { + region = geo.rectUnion(region, rect); + } + + this.set('dirtyRegion', region); + this.set('dirty', true); + }, + + _resizeCanvas: function (oldSize) { var size = this.get('contentSize'); if (geo.sizeEqualToSize(size, oldSize)) { return; // No change } + this.renderTexture.set('contentSize', size); this.set('dirty', true); }, - update: function() { + update: function () { }, - visit: function(context) { + visit: function (context) { if (!this.visible) { return; } @@ -94,50 +135,101 @@ var BatchNode = Node.extend(/** @lends cocos.nodes.BatchNode# */{ this.transform(context); + var rect = this.get('dirtyRegion'); // Only redraw if something changed if (this.dirty) { - this.renderTexture.clear(); + + if (rect) { + if (this.get('partialDraw')) { + // Clip region to visible area + var s = require('../Director').Director.get('sharedDirector').get('winSize'), + p = this.get('position'); + var r = new geo.Rect( + 0, 0, + s.width, s.height + ); + r = geo.rectApplyAffineTransform(r, this.worldToNodeTransform()); + rect = geo.rectIntersection(r, rect); + } + + this.renderTexture.clear(rect); + + this.renderTexture.context.save(); + this.renderTexture.context.beginPath(); + this.renderTexture.context.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + this.renderTexture.context.clip(); + this.renderTexture.context.closePath(); + } else { + this.renderTexture.clear(); + } + for (var i = 0, childLen = this.children.length; i < childLen; i++) { var c = this.children[i]; if (c == this.renderTexture) { continue; } - c.visit(this.renderTexture.context); + + // Draw children inside rect + if (!rect || geo.rectOverlapsRect(c.get('boundingBox'), rect)) { + c.visit(this.renderTexture.context, rect); + } + } + + if (SHOW_REDRAW_REGIONS) { + if (rect) { + this.renderTexture.context.beginPath(); + this.renderTexture.context.rect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + this.renderTexture.context.fillStyle = "rgba(0, 0, 255, 0.5)"; + this.renderTexture.context.fill(); + this.renderTexture.context.closePath(); + } + } + + if (rect) { + this.renderTexture.context.restore(); } + this.set('dirty', false); + this.set('dirtyRegion', null); } this.renderTexture.visit(context); - this.draw(context); - context.restore(); - }, + }, - draw: function(ctx) { + draw: function (ctx) { + }, + + onEnter: function () { + if (this.get('partialDraw')) { + evt.addListener(this.get('parent'), 'istransformdirty_changed', util.callback(this, function () { + var box = this.get('visibleRect'); + this.addDirtyRegion(box); + })); + } } }); -var SpriteBatchNode = BatchNode.extend({ +var SpriteBatchNode = BatchNode.extend(/** @lends cocos.nodes.SpriteBatchNode# */{ textureAtlas: null, /** - * A BatchNode that accepts only Sprite using the same texture - * * @memberOf cocos.nodes - * @constructs + * @class A BatchNode that accepts only Sprite using the same texture * @extends cocos.nodes.BatchNode + * @constructs * * @opt {String} file (Optional) Path to image to use as sprite atlas * @opt {Texture2D} texture (Optional) Texture to use as sprite atlas * @opt {cocos.TextureAtlas} textureAtlas (Optional) TextureAtlas to use as sprite atlas */ - init: function(opts) { - @super; + init: function (opts) { + SpriteBatchNode.superclass.init.call(this, opts); - var file = opts['file'], - textureAtlas = opts['textureAtlas'], - texture = opts['texture']; + var file = opts.file, + textureAtlas = opts.textureAtlas, + texture = opts.texture; if (file || texture) { textureAtlas = TextureAtlas.create({file: file, texture: texture}); @@ -150,9 +242,17 @@ var SpriteBatchNode = BatchNode.extend({ * @getter texture * @type cocos.Texture2D */ - get_texture: function() { - return this.textureAtlas ? this.textureAtlas.texture : null; - } + get_texture: function () { + return this.textureAtlas ? this.textureAtlas.texture : null; + }, + + set_opacity: function (newOpacity) { + this.opacity = newOpacity; + for (var i = 0, len = this.children.length; i < len; i++) { + var child = this.children[i]; + child.set('opacity', newOpacity); + } + } }); diff --git a/src/libs/cocos2d/nodes/Label.js b/src/libs/cocos2d/nodes/Label.js index cbe3559..3e6e2ce 100644 --- a/src/libs/cocos2d/nodes/Label.js +++ b/src/libs/cocos2d/nodes/Label.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), console = require('system').console, Director = require('../Director').Director, @@ -21,10 +25,10 @@ var Label = Node.extend(/** @lends cocos.nodes.Label# */{ * @opt {String} [fontName="Helvetica"] The name of the font to use * @opt {String} [fontColor="white"] The color of the text */ - init: function(opts) { - @super; + init: function (opts) { + Label.superclass.init.call(this, opts); - util.each('fontSize fontName fontColor string'.w(), util.callback(this, function(name) { + util.each('fontSize fontName fontColor string'.w(), util.callback(this, function (name) { // Set property on init if (opts[name]) { this.set(name, opts[name]); @@ -41,11 +45,20 @@ var Label = Node.extend(/** @lends cocos.nodes.Label# */{ * @getter font * @type String */ - get_font: function(key) { + get_font: function (key) { return this.get('fontSize') + 'px ' + this.get('fontName'); }, - draw: function(context) { + draw: function (context) { + if (FLIP_Y_AXIS) { + context.save(); + + // Flip Y axis + context.scale(1, -1); + context.translate(0, -this.get('fontSize')); + } + + context.fillStyle = this.get('fontColor'); context.font = this.get('font'); context.textBaseline = 'top'; @@ -54,12 +67,16 @@ var Label = Node.extend(/** @lends cocos.nodes.Label# */{ } else if (context.mozDrawText) { context.mozDrawText(this.get('string')); } + + if (FLIP_Y_AXIS) { + context.restore(); + } }, /** * @private */ - _updateLabelContentSize: function() { + _updateLabelContentSize: function () { var ctx = Director.get('sharedDirector').get('context'); var size = {width: 0, height: this.get('fontSize')}; diff --git a/src/libs/cocos2d/nodes/LabelAtlas.js b/src/libs/cocos2d/nodes/LabelAtlas.js new file mode 100644 index 0000000..5e9fc9d --- /dev/null +++ b/src/libs/cocos2d/nodes/LabelAtlas.js @@ -0,0 +1,74 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var AtlasNode = require('./AtlasNode').AtlasNode, + Sprite = require('./Sprite').Sprite, + geo = require('geometry'); + +var LabelAtlas = AtlasNode.extend(/** @lends cocos.nodes.LabelAtlas# */{ + string: '', + + mapStartChar: '', + + /** + * @memberOf cocos.nodes + * @extends cocos.nodes.BatchNode + * @constructs + * + * @opt {String} [string=] Initial text to draw + * @opt {String} charMapFile + * @opt {Integer} itemWidth + * @opt {Integer} itemHeight + * @opt {String} startCharMap Single character + */ + init: function (opts) { + LabelAtlas.superclass.init.call(this, { + file: opts.charMapFile, + itemWidth: opts.itemWidth, + itemHeight: opts.itemHeight, + itemsToRender: opts.string.length, + size: new geo.Size(opts.itemWidth * opts.string.length, opts.itemHeight) + }); + + + this.mapStartChar = opts.startCharMap.charCodeAt(0); + this.set('string', opts.string); + }, + + updateAtlasValue: function () { + var n = this.string.length, + s = this.get('string'); + + // FIXME this should reuse children to improve performance + while (this.children.length > 0) { + this.removeChild(this.children[0]); + } + for (var i = 0; i < n; i++) { + var a = s.charCodeAt(i) - this.mapStartChar, + row = (a % this.itemsPerRow), + col = Math.floor(a / this.itemsPerRow); + + var left = row * this.itemWidth, + top = col * this.itemHeight; + + var tile = Sprite.create({rect: new geo.Rect(left, top, this.itemWidth, this.itemHeight), + textureAtlas: this.textureAtlas}); + + tile.set('position', new geo.Point(i * this.itemWidth, 0)); + tile.set('anchorPoint', new geo.Point(0, 0)); + tile.set('opacity', this.get('opacity')); + + this.addChild({child: tile}); + } + }, + + set_string: function (newString) { + this.string = newString; + + this.updateAtlasValue(); + } +}); + + +exports.LabelAtlas = LabelAtlas; diff --git a/src/libs/cocos2d/nodes/Layer.js b/src/libs/cocos2d/nodes/Layer.js index 47dd0b7..be98b02 100644 --- a/src/libs/cocos2d/nodes/Layer.js +++ b/src/libs/cocos2d/nodes/Layer.js @@ -1,6 +1,10 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var Node = require('./Node').Node, util = require('util'), - event = require('event'), + evt = require('events'), Director = require('../Director').Director, ccp = require('geometry').ccp, EventDispatcher = require('../EventDispatcher').EventDispatcher; @@ -18,8 +22,8 @@ var Layer = Node.extend(/** @lends cocos.nodes.Layer# */{ * @constructs * @extends cocos.nodes.Node */ - init: function() { - @super; + init: function () { + Layer.superclass.init.call(this); var s = Director.get('sharedDirector').get('winSize'); @@ -27,10 +31,10 @@ var Layer = Node.extend(/** @lends cocos.nodes.Layer# */{ this.anchorPoint = ccp(0.5, 0.5); this.set('contentSize', s); - event.addListener(this, 'ismouseenabled_changed', util.callback(this, function() { + evt.addListener(this, 'ismouseenabled_changed', util.callback(this, function () { if (this.isRunning) { if (this.isMouseEnabled) { - EventDispatcher.get('sharedDispatcher').addMouseDelegate({delegate: this, priority:this.get('mouseDelegatePriority')}); + EventDispatcher.get('sharedDispatcher').addMouseDelegate({delegate: this, priority: this.get('mouseDelegatePriority')}); } else { EventDispatcher.get('sharedDispatcher').removeMouseDelegate({delegate: this}); } @@ -38,10 +42,10 @@ var Layer = Node.extend(/** @lends cocos.nodes.Layer# */{ })); - event.addListener(this, 'iskeyboardenabled_changed', util.callback(this, function() { + evt.addListener(this, 'iskeyboardenabled_changed', util.callback(this, function () { if (this.isRunning) { if (this.isKeyboardEnabled) { - EventDispatcher.get('sharedDispatcher').addKeyboardDelegate({delegate: this, priority:this.get('keyboardDelegatePriority')}); + EventDispatcher.get('sharedDispatcher').addKeyboardDelegate({delegate: this, priority: this.get('keyboardDelegatePriority')}); } else { EventDispatcher.get('sharedDispatcher').removeKeyboardDelegate({delegate: this}); } @@ -49,18 +53,18 @@ var Layer = Node.extend(/** @lends cocos.nodes.Layer# */{ })); }, - onEnter: function() { + onEnter: function () { if (this.isMouseEnabled) { - EventDispatcher.get('sharedDispatcher').addMouseDelegate({delegate: this, priority:this.get('mouseDelegatePriority')}); + EventDispatcher.get('sharedDispatcher').addMouseDelegate({delegate: this, priority: this.get('mouseDelegatePriority')}); } if (this.isKeyboardEnabled) { - EventDispatcher.get('sharedDispatcher').addKeyboardDelegate({delegate: this, priority:this.get('keyboardDelegatePriority')}); + EventDispatcher.get('sharedDispatcher').addKeyboardDelegate({delegate: this, priority: this.get('keyboardDelegatePriority')}); } - - @super; + + Layer.superclass.onEnter.call(this); }, - onExit: function() { + onExit: function () { if (this.isMouseEnabled) { EventDispatcher.get('sharedDispatcher').removeMouseDelegate({delegate: this}); } @@ -68,7 +72,7 @@ var Layer = Node.extend(/** @lends cocos.nodes.Layer# */{ EventDispatcher.get('sharedDispatcher').removeKeyboardDelegate({delegate: this}); } - @super; + Layer.superclass.onExit.call(this); } }); diff --git a/src/libs/cocos2d/nodes/Menu.js b/src/libs/cocos2d/nodes/Menu.js index 3b79424..329889d 100644 --- a/src/libs/cocos2d/nodes/Menu.js +++ b/src/libs/cocos2d/nodes/Menu.js @@ -1,24 +1,31 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), Layer = require('./Layer').Layer, Director = require('../Director').Director, MenuItem = require('./MenuItem').MenuItem, geom = require('geometry'), ccp = geom.ccp; -/** @private - * @constant */ +/** + * @private + * @constant + */ var kMenuStateWaiting = 0; -/** @private - * @constant */ +/** + * @private + * @constant + */ var kMenuStateTrackingTouch = 1; - + var Menu = Layer.extend(/** @lends cocos.nodes.Menu# */{ - mouseDelegatePriority: (-Number.MAX_VALUE +1), - state: kMenuStateWaiting, - selectedItem: null, - opacuty: 255, - color: null, + mouseDelegatePriority: (-Number.MAX_VALUE + 1), + state: kMenuStateWaiting, + selectedItem: null, + color: null, /** * A fullscreen node used to render a selection of menu options @@ -29,42 +36,42 @@ var Menu = Layer.extend(/** @lends cocos.nodes.Menu# */{ * * @opt {cocos.nodes.MenuItem[]} items An array of MenuItems to draw on the menu */ - init: function(opts) { - @super; + init: function (opts) { + Menu.superclass.init.call(this, opts); - var items = opts['items']; + var items = opts.items; - this.set('isMouseEnabled', true); - + this.set('isMouseEnabled', true); + var s = Director.get('sharedDirector').get('winSize'); - this.set('isRelativeAnchorPoint', false); - this.anchorPoint = ccp(0.5, 0.5); - this.set('contentSize', s); + this.set('isRelativeAnchorPoint', false); + this.anchorPoint = ccp(0.5, 0.5); + this.set('contentSize', s); - this.set('position', ccp(s.width /2, s.height /2)); + this.set('position', ccp(s.width / 2, s.height / 2)); - if (items) { - var z = 0; - util.each(items, util.callback(this, function(item) { - this.addChild({child: item, z:z++}); - })); - } + if (items) { + var z = 0; + util.each(items, util.callback(this, function (item) { + this.addChild({child: item, z: z++}); + })); + } - }, + }, - addChild: function(opts) { - if (!opts['child'] instanceof MenuItem) { - throw "Menu only supports MenuItem objects as children"; - } + addChild: function (opts) { + if (!opts.child instanceof MenuItem) { + throw "Menu only supports MenuItem objects as children"; + } - return @super; + Menu.superclass.addChild.call(this, opts); }, - itemForMouseEvent: function(event) { - var location = Director.get('sharedDirector').convertEventToCanvas(event); + itemForMouseEvent: function (event) { + var location = event.locationInCanvas; var children = this.get('children'); for (var i = 0, len = children.length; i < len; i++) { @@ -86,29 +93,32 @@ var Menu = Layer.extend(/** @lends cocos.nodes.Menu# */{ return null; }, - mouseUp: function(event) { - if (this.selectedItem) { - this.selectedItem.set('isSelected', false); - this.selectedItem.activate(); + mouseUp: function (event) { + var selItem = this.get('selectedItem'); - return true; + if (selItem) { + selItem.unselected(); + selItem.activate(); } if (this.state != kMenuStateWaiting) { this.set('state', kMenuStateWaiting); } - + if (selItem) { + return true; + } return false; }, - mouseDown: function(event) { + mouseDown: function (event) { if (this.state != kMenuStateWaiting || !this.visible) { return false; } - var selectedItem = this.set('selectedItem', this.itemForMouseEvent(event)); + var selectedItem = this.itemForMouseEvent(event); + this.set('selectedItem', selectedItem); if (selectedItem) { - selectedItem.set('isSelected', true); + selectedItem.selected() this.set('state', kMenuStateTrackingTouch); return true; @@ -116,16 +126,17 @@ var Menu = Layer.extend(/** @lends cocos.nodes.Menu# */{ return false; }, - mouseDragged: function(event) { + + mouseDragged: function (event) { var currentItem = this.itemForMouseEvent(event); if (currentItem != this.selectedItem) { if (this.selectedItem) { - this.selectedItem.set('isSelected', false); + this.selectedItem.unselected(); } this.set('selectedItem', currentItem); if (this.selectedItem) { - this.selectedItem.set('isSelected', true); + this.selectedItem.selected(); } } diff --git a/src/libs/cocos2d/nodes/MenuItem.js b/src/libs/cocos2d/nodes/MenuItem.js index 62ed0f3..d73ad03 100644 --- a/src/libs/cocos2d/nodes/MenuItem.js +++ b/src/libs/cocos2d/nodes/MenuItem.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), Node = require('./Node').Node, Sprite = require('./Sprite').Sprite, @@ -5,9 +9,9 @@ var util = require('util'), ccp = require('geometry').ccp; var MenuItem = Node.extend(/** @lends cocos.nodes.MenuItem# */{ - isEnabled: true, - isSelected: false, - callback: null, + isEnabled: true, + isSelected: false, + callback: null, /** * Base class for any buttons or options in a menu @@ -18,39 +22,47 @@ var MenuItem = Node.extend(/** @lends cocos.nodes.MenuItem# */{ * * @opt {Function} callback Function to call when menu item is activated */ - init: function(opts) { - @super; + init: function (opts) { + MenuItem.superclass.init.call(this, opts); - var callback = opts['callback']; + var callback = opts.callback; - this.set('anchorPoint', ccp(0.5, 0.5)); - this.set('callback', callback); - }, + this.set('anchorPoint', ccp(0.5, 0.5)); + this.set('callback', callback); + }, - activate: function() { - if (this.isEnabled && this.callback) { - this.callback(this); - } - }, + activate: function () { + if (this.isEnabled && this.callback) { + this.callback(this); + } + }, /** * @getter rect * @type geometry.Rect */ - get_rect: function() { - return rectMake( - this.position.x - this.contentSize.width * this.anchorPoint.x, - this.position.y - this.contentSize.height * this.anchorPoint.y, - this.contentSize.width, - this.contentSize.height - ) - } + get_rect: function () { + return rectMake( + this.position.x - this.contentSize.width * this.anchorPoint.x, + this.position.y - this.contentSize.height * this.anchorPoint.y, + this.contentSize.width, + this.contentSize.height + ); + }, + + selected: function () { + this.isSelected = true; + }, + + unselected: function () { + this.isSelected = false; + } }); var MenuItemSprite = MenuItem.extend(/** @lends cocos.nodes.MenuItemSprite# */{ - normalImage: null, - selectedImage: null, - disabledImage: null, + normalImage: null, + selectedImage: null, + disabledImage: null, /** * A menu item that accepts any cocos.nodes.Node @@ -63,35 +75,93 @@ var MenuItemSprite = MenuItem.extend(/** @lends cocos.nodes.MenuItemSprite# */{ * @opt {cocos.nodes.Node} selectedImage Node to draw when menu item is selected * @opt {cocos.nodes.Node} disabledImage Node to draw when menu item is disabled */ - init: function(opts) { - @super; - - var normalImage = opts['normalImage'], - selectedImage = opts['selectedImage'], - disabledImage = opts['disabledImage']; - - this.set('normalImage', normalImage); - this.set('selectedImage', selectedImage); - this.set('disabledImage', disabledImage); - - this.set('contentSize', normalImage.get('contentSize')); - }, - - draw: function(ctx) { - if (this.isEnabled) { - if (this.isSelected) { - this.selectedImage.draw(ctx); - } else { - this.normalImage.draw(ctx); - } - } else { - if (this.disabledImage != null) { - this.disabledImage.draw(ctx); - } else { - this.normalImage.draw(ctx); - } - } - } + init: function (opts) { + MenuItemSprite.superclass.init.call(this, opts); + + var normalImage = opts.normalImage, + selectedImage = opts.selectedImage, + disabledImage = opts.disabledImage; + + this.set('normalImage', normalImage); + this.set('selectedImage', selectedImage); + this.set('disabledImage', disabledImage); + + this.set('contentSize', normalImage.get('contentSize')); + }, + + set_normalImage: function (image) { + if (image != this.normalImage) { + image.set('anchorPoint', ccp(0, 0)); + image.set('visible', true); + this.removeChild({child: this.normalImage, cleanup: true}); + this.addChild(image); + + this.normalImage = image; + } + }, + + set_selectedImage: function (image) { + if (image != this.selectedImage) { + image.set('anchorPoint', ccp(0, 0)); + image.set('visible', false); + this.removeChild({child: this.selectedImage, cleanup: true}); + this.addChild(image); + + this.selectedImage = image; + } + }, + + set_disabledImage: function (image) { + if (image != this.disabledImage) { + image.set('anchorPoint', ccp(0, 0)); + image.set('visible', false); + this.removeChild({child: this.disabledImage, cleanup: true}); + this.addChild(image); + + this.disabledImage = image; + } + }, + + selected: function () { + MenuItemSprite.superclass.selected.call(this); + + if (this.selectedImage) { + this.normalImage.set('visible', false); + this.selectedImage.set('visible', true); + if (this.disabledImage) this.disabledImage.set('visible', false); + } else { + this.normalImage.set('visible', true); + if (this.disabledImage) this.disabledImage.set('visible', false); + } + }, + + unselected: function () { + MenuItemSprite.superclass.unselected.call(this); + + this.normalImage.set('visible', true); + if (this.selectedImage) this.selectedImage.set('visible', false); + if (this.disabledImage) this.disabledImage.set('visible', false); + }, + + set_isEnabled: function (enabled) { + this.isEnabled = enabled; + + if (enabled) { + this.normalImage.set('visible', true); + if (this.selectedImage) this.selectedImage.set('visible', false); + if (this.disabledImage) this.disabledImage.set('visible', false); + } else { + if (this.disabledImage) { + this.normalImage.set('visible', false); + if (this.selectedImage) this.selectedImage.set('visible', false); + this.disabledImage.set('visible', true); + } else { + this.normalImage.set('visible', true); + if (this.selectedImage) this.selectedImage.set('visible', false); + } + } + } + }); var MenuItemImage = MenuItemSprite.extend(/** @lends cocos.nodes.MenuItemImage# */{ @@ -107,21 +177,21 @@ var MenuItemImage = MenuItemSprite.extend(/** @lends cocos.nodes.MenuItemImage# * @opt {String} selectedImage Image file to draw when menu item is selected * @opt {String} disabledImage Image file to draw when menu item is disabled */ - init: function(opts) { - var normalI = opts['normalImage'], - selectedI = opts['selectedImage'], - disabledI = opts['disabledImage'], - callback = opts['callback']; + init: function (opts) { + var normalI = opts.normalImage, + selectedI = opts.selectedImage, + disabledI = opts.disabledImage, + callback = opts.callback; - var normalImage = Sprite.create({file: normalI}), - selectedImage = Sprite.create({file: selectedI}), - disabledImage = null; + var normalImage = Sprite.create({file: normalI}), + selectedImage = Sprite.create({file: selectedI}), + disabledImage = null; - if (disabledI) { - disabledImage = Sprite.create({file: disabledI}) - } + if (disabledI) { + disabledImage = Sprite.create({file: disabledI}); + } - return @super({normalImage: normalImage, selectedImage: selectedImage, disabledImage: disabledImage, callback: callback}); + return MenuItemImage.superclass.init.call(this, {normalImage: normalImage, selectedImage: selectedImage, disabledImage: disabledImage, callback: callback}); } }); diff --git a/src/libs/cocos2d/nodes/Node.js b/src/libs/cocos2d/nodes/Node.js index be1471b..d2c763a 100644 --- a/src/libs/cocos2d/nodes/Node.js +++ b/src/libs/cocos2d/nodes/Node.js @@ -1,22 +1,88 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - event = require('event'), + evt = require('events'), Scheduler = require('../Scheduler').Scheduler, ActionManager = require('../ActionManager').ActionManager, - geom = require('geometry'), ccp = geom.ccp; + geo = require('geometry'), ccp = geo.ccp; var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ isCocosNode: true, + + /** + * Is the node visible + * @type boolean + */ visible: true, + + /** + * Position relative to parent node + * @type geometry.Point + */ position: null, + + /** + * Parent node + * @type cocos.nodes.Node + */ parent: null, + + /** + * Unique tag to identify the node + * @type * + */ tag: null, + + /** + * Size of the node + * @type geometry.Size + */ contentSize: null, + + /** + * Nodes Z index. i.e. draw order + * @type Integer + */ zOrder: 0, + + /** + * Anchor point for scaling and rotation. 0x0 is top left and 1x1 is bottom right + * @type geometry.Point + */ anchorPoint: null, + + /** + * Anchor point for scaling and rotation in pixels from top left + * @type geometry.Point + */ anchorPointInPixels: null, + + /** + * Rotation angle in degrees + * @type Float + */ rotation: 0, + + /** + * X scale factor + * @type Float + */ scaleX: 1, + + /** + * Y scale factor + * @type Float + */ scaleY: 1, + + /** + * Opacity of the Node. 0 is totally transparent, 255 is totally opaque + * @type Float + */ + opacity: 255, + isRunning: false, isRelativeAnchorPoint: true, @@ -27,28 +93,29 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ /** * The child Nodes - * @type {cocos.nodes.Node[]} + * @type cocos.nodes.Node[] */ children: null, /** - * The base class all visual elements extend from * @memberOf cocos.nodes - * @constructs + * @class The base class all visual elements extend from * @extends BObject + * @constructs */ - init: function() { + init: function () { + Node.superclass.init.call(this); this.set('contentSize', {width: 0, height: 0}); this.anchorPoint = ccp(0.5, 0.5); this.anchorPointInPixels = ccp(0, 0); - this.position = ccp(0,0); + this.position = ccp(0, 0); this.children = []; - util.each(['scaleX', 'scaleY', 'rotation', 'position', 'anchorPoint', 'contentSize', 'isRelativeAnchorPoint'], util.callback(this, function(key) { - event.addListener(this, key.toLowerCase() + '_changed', util.callback(this, this._dirtyTransform)); + util.each(['scaleX', 'scaleY', 'rotation', 'position', 'anchorPoint', 'contentSize', 'isRelativeAnchorPoint'], util.callback(this, function (key) { + evt.addListener(this, key.toLowerCase() + '_changed', util.callback(this, this._dirtyTransform)); })); - event.addListener(this, 'anchorpoint_changed', util.callback(this, this._updateAnchorPointInPixels)); - event.addListener(this, 'contentsize_changed', util.callback(this, this._updateAnchorPointInPixels)); + evt.addListener(this, 'anchorpoint_changed', util.callback(this, this._updateAnchorPointInPixels)); + evt.addListener(this, 'contentsize_changed', util.callback(this, this._updateAnchorPointInPixels)); }, /** @@ -56,7 +123,7 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ * anchorPointInPixels property * @private */ - _updateAnchorPointInPixels: function() { + _updateAnchorPointInPixels: function () { var ap = this.get('anchorPoint'), cs = this.get('contentSize'); this.set('anchorPointInPixels', ccp(cs.width * ap.x, cs.height * ap.y)); @@ -70,23 +137,23 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ * @opt {Integer|String} [tag] A tag to reference the child with * @returns {cocos.nodes.Node} The node the child was added to. i.e. 'this' */ - addChild: function(opts) { + addChild: function (opts) { if (opts.isCocosNode) { - return arguments.callee.call(this, {child:opts}); + return this.addChild({child: opts}); } - var child = opts['child'], - z = opts['z'], - tag = opts['tag']; + var child = opts.child, + z = opts.z, + tag = opts.tag; - if (z == undefined) { + if (z === undefined || z === null) { z = child.get('zOrder'); } //this.insertChild({child: child, z:z}); var added = false; - + for (var i = 0, childLen = this.children.length; i < childLen; i++) { var c = this.children[i]; if (c.zOrder > z) { @@ -110,8 +177,8 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ return this; }, - getChild: function(opts) { - var tag = opts['tag']; + getChild: function (opts) { + var tag = opts.tag; for (var i = 0; i < this.children.length; i++) { if (this.children[i].tag == tag) { @@ -122,7 +189,11 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ return null; }, - removeChild: function(opts) { + removeChild: function (opts) { + if (opts.isCocosNode) { + return this.removeChild({child: opts}); + } + var child = opts.child, cleanup = opts.cleanup; @@ -138,7 +209,26 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ } }, - detatchChild: function(opts) { + removeChildren: function(opts) { + var children = this.get('children'), + isRunning = this.get('isRunning'); + + // Perform cleanup on each child but can't call removeChild() + // due to Array.splice's destructive nature during iteration. + for (var i = 0; i < children.length; i++) { + if (opts.cleanup) { + children[i].cleanup(); + } + if (isRunning) { + children[i].onExit(); + } + children[i].set('parent', null); + } + // Now safe to empty children list + this.children = []; + }, + + detatchChild: function (opts) { var child = opts.child, cleanup = opts.cleanup; @@ -158,9 +248,9 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ children.splice(idx, 1); }, - reorderChild: function(opts) { - var child = opts['child'], - z = opts['z']; + reorderChild: function (opts) { + var child = opts.child, + z = opts.z; var pos = this.children.indexOf(child); if (pos == -1) { @@ -188,7 +278,15 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ } }, - draw: function(context) { + /** + * Draws the node. Override to do custom drawing. If it's less efficient to + * draw only the area inside the rect then don't bother. The result will be + * clipped to that area anyway. + * + * @param {CanvasRenderingContext2D|WebGLRenderingContext} context Canvas rendering context + * @param {geometry.Rect} rect Rectangular region that needs redrawing. Limit drawing to this area only if it's more efficient to do so. + */ + draw: function (context, rect) { // All draw code goes here }, @@ -196,9 +294,9 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ * @getter scale * @type Float */ - get_scale: function() { + get_scale: function () { if (this.scaleX != this.scaleY) { - throw "scaleX and scaleY aren't identical" + throw "scaleX and scaleY aren't identical"; } return this.scaleX; @@ -208,14 +306,14 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ * @setter scale * @type Float */ - set_scale: function(val) { + set_scale: function (val) { this.set('scaleX', val); this.set('scaleY', val); }, - - scheduleUpdate: function(opts) { - var opts = opts || {}, - priority = opts['priority'] || 0; + + scheduleUpdate: function (opts) { + opts = opts || {}; + var priority = opts.priority || 0; Scheduler.get('sharedScheduler').scheduleUpdate({target: this, priority: priority, paused: !this.get('isRunning')}); }, @@ -225,8 +323,10 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ * * @event */ - onEnter: function() { - util.each(this.children, function(child) { child.onEnter(); }); + onEnter: function () { + util.each(this.children, function (child) { + child.onEnter(); + }); this.resumeSchedulerAndActions(); this.set('isRunning', true); @@ -237,35 +337,42 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ * * @event */ - onExit: function() { + onExit: function () { this.pauseSchedulerAndActions(); this.set('isRunning', false); - util.each(this.children, function(child) { child.onExit(); }); + util.each(this.children, function (child) { + child.onExit(); + }); }, - cleanup: function() { + cleanup: function () { this.stopAllActions(); this.unscheduleAllSelectors(); - util.each(this.children, function(child) { child.cleanup(); }); + util.each(this.children, function (child) { + child.cleanup(); + }); }, - resumeSchedulerAndActions: function() { + resumeSchedulerAndActions: function () { Scheduler.get('sharedScheduler').resumeTarget(this); ActionManager.get('sharedManager').resumeTarget(this); }, - pauseSchedulerAndActions: function() { + pauseSchedulerAndActions: function () { Scheduler.get('sharedScheduler').pauseTarget(this); ActionManager.get('sharedManager').pauseTarget(this); }, - unscheduleAllSelectors: function() { + unscheduleSelector: function (selector) { + Scheduler.get('sharedScheduler').unschedule({target: this, method: selector}); + }, + unscheduleAllSelectors: function () { Scheduler.get('sharedScheduler').unscheduleAllSelectorsForTarget(this); }, - stopAllActions: function() { + stopAllActions: function () { ActionManager.get('sharedManager').removeAllActionsFromTarget(this); }, - visit: function(context) { + visit: function (context, rect) { if (!this.visible) { return; } @@ -274,144 +381,205 @@ var Node = BObject.extend(/** @lends cocos.nodes.Node# */{ this.transform(context); + // Set alpha value (global only for now) + context.globalAlpha = this.get('opacity') / 255.0; + + // Adjust redraw region by nodes position + if (rect) { + var pos = this.get('position'); + rect = new geo.Rect(rect.origin.x - pos.x, rect.origin.y - pos.y, rect.size.width, rect.size.height); + } + // Draw background nodes - util.each(this.children, function(child, i) { + util.each(this.children, function (child, i) { if (child.zOrder < 0) { - child.visit(context); + child.visit(context, rect); } }); - - this.draw(context); + + this.draw(context, rect); // Draw foreground nodes - util.each(this.children, function(child, i) { + util.each(this.children, function (child, i) { if (child.zOrder >= 0) { - child.visit(context); + child.visit(context, rect); } }); context.restore(); }, - transform: function(context) { + transform: function (context) { // Translate - if (this.isRelativeAnchorPoint && (this.anchorPointInPixels.x != 0 || this.anchorPointInPixels != 0)) { + if (this.isRelativeAnchorPoint && (this.anchorPointInPixels.x !== 0 || this.anchorPointInPixels.y !== 0)) { context.translate(Math.round(-this.anchorPointInPixels.x), Math.round(-this.anchorPointInPixels.y)); } - if (this.anchorPointInPixels.x != 0 || this.anchorPointInPixels != 0) { + if (this.anchorPointInPixels.x !== 0 || this.anchorPointInPixels.y !== 0) { context.translate(Math.round(this.position.x + this.anchorPointInPixels.x), Math.round(this.position.y + this.anchorPointInPixels.y)); } else { context.translate(Math.round(this.position.x), Math.round(this.position.y)); } // Rotate - context.rotate(geom.degressToRadians(this.get('rotation'))); + context.rotate(geo.degreesToRadians(this.get('rotation'))); // Scale context.scale(this.scaleX, this.scaleY); - - if (this.anchorPointInPixels.x != 0 || this.anchorPointInPixels != 0) { + + if (this.anchorPointInPixels.x !== 0 || this.anchorPointInPixels.y !== 0) { context.translate(Math.round(-this.anchorPointInPixels.x), Math.round(-this.anchorPointInPixels.y)); } }, - runAction: function(action) { + runAction: function (action) { ActionManager.get('sharedManager').addAction({action: action, target: this, paused: this.get('isRunning')}); }, - - nodeToParentTransform: function() { + + /** + * @opts {String} tag Tag of the action to return + */ + getAction: function(opts) { + return ActionManager.get('sharedManager').getActionFromTarget({target: this, tag: opts.tag}); + }, + + nodeToParentTransform: function () { if (this.isTransformDirty) { - this.transformMatrix = geom.affineTransformIdentity(); + this.transformMatrix = geo.affineTransformIdentity(); - if (!this.isRelativeAnchorPoint && !geom.pointEqualToPoint(this.anchorPointInPixels, ccp(0,0))) { - this.transformMatrix = geom.affineTransformTranslate(this.transformMatrix, this.anchorPointInPixels.x, this.anchorPointInPixels.y); + if (!this.isRelativeAnchorPoint && !geo.pointEqualToPoint(this.anchorPointInPixels, ccp(0, 0))) { + this.transformMatrix = geo.affineTransformTranslate(this.transformMatrix, this.anchorPointInPixels.x, this.anchorPointInPixels.y); } - - if(!geom.pointEqualToPoint(this.position, ccp(0,0))) { - this.transformMatrix = geom.affineTransformTranslate(this.transformMatrix, this.position.x, this.position.y); + + if (!geo.pointEqualToPoint(this.position, ccp(0, 0))) { + this.transformMatrix = geo.affineTransformTranslate(this.transformMatrix, this.position.x, this.position.y); } - if(this.rotation != 0) { - this.transformMatrix = geom.affineTransformRotate(this.transformMatrix, -geom.degressToRadians(this.rotation)); + if (this.rotation !== 0) { + this.transformMatrix = geo.affineTransformRotate(this.transformMatrix, -geo.degreesToRadians(this.rotation)); } - if(!(this.scaleX == 1 && this.scaleY == 1)) { - this.transformMatrix = geom.affineTransformScale(this.transformMatrix, this.scaleX, this.scaleY); + if (!(this.scaleX == 1 && this.scaleY == 1)) { + this.transformMatrix = geo.affineTransformScale(this.transformMatrix, this.scaleX, this.scaleY); } - - if(!geom.pointEqualToPoint(this.anchorPointInPixels, ccp(0,0))) { - this.transformMatrix = geom.affineTransformTranslate(this.transformMatrix, -this.anchorPointInPixels.x, -this.anchorPointInPixels.y); + + if (!geo.pointEqualToPoint(this.anchorPointInPixels, ccp(0, 0))) { + this.transformMatrix = geo.affineTransformTranslate(this.transformMatrix, -this.anchorPointInPixels.x, -this.anchorPointInPixels.y); } - + this.set('isTransformDirty', false); - + } return this.transformMatrix; }, - parentToNodeTransform: function() { + parentToNodeTransform: function () { // TODO }, - nodeToWorldTransform: function() { + nodeToWorldTransform: function () { var t = this.nodeToParentTransform(); var p; for (p = this.get('parent'); p; p = p.get('parent')) { - t = geom.affineTransformConcat(t, p.nodeToParentTransform()); + t = geo.affineTransformConcat(t, p.nodeToParentTransform()); } return t; }, - worldToNodeTransform: function() { - return geom.affineTransformInvert(this.nodeToWorldTransform()); + worldToNodeTransform: function () { + return geo.affineTransformInvert(this.nodeToWorldTransform()); + }, + + convertToNodeSpace: function (worldPoint) { + return geo.pointApplyAffineTransform(worldPoint, this.worldToNodeTransform()); }, - convertToNodeSpace: function(worldPoint) { - return geom.pointApplyAffineTransform(worldPoint, this.worldToNodeTransform()); + /** + * @getter boundingBox + * @type geometry.Rect + */ + get_boundingBox: function () { + var cs = this.get('contentSize'); + var rect = geo.rectMake(0, 0, cs.width, cs.height); + rect = geo.rectApplyAffineTransform(rect, this.nodeToParentTransform()); + return rect; }, /** - * @getter acceptsFirstResponder - * @type Boolean + * @getter worldBoundingBox + * @type geometry.Rect */ - get_acceptsFirstResponder: function() { - return false; + get_worldBoundingBox: function () { + var cs = this.get('contentSize'); + + var rect = geo.rectMake(0, 0, cs.width, cs.height); + rect = geo.rectApplyAffineTransform(rect, this.nodeToWorldTransform()); + return rect; }, /** - * @getter becomeFirstResponder - * @type Boolean + * The area of the node currently visible on screen. Returns an rect even + * if visible is false. + * + * @getter visibleRect + * @type geometry.Rect */ - get_becomeFirstResponder: function() { - return true; + get_visibleRect: function () { + var s = require('../Director').Director.get('sharedDirector').get('winSize'); + var rect = new geo.Rect( + 0, 0, + s.width, s.height + ); + + return geo.rectApplyAffineTransform(rect, this.worldToNodeTransform()); }, /** - * @getter resignFirstResponder - * @type Boolean + * @private */ - get_resignFirstResponder: function() { - return true; + _dirtyTransform: function () { + this.set('isTransformDirty', true); }, /** - * @getter boundingBox - * @type geometry.Rect + * Schedules a custom method with an interval time in seconds. + * If time is 0 it will be ticked every frame. + * If time is 0, it is recommended to use 'scheduleUpdate' instead. + * + * If the method is already scheduled, then the interval parameter will + * be updated without scheduling it again. + * + * @opt {String|Function} method Function of method name to schedule + * @opt {Float} [interval=0] Interval in seconds */ - get_boundingBox: function() { - var cs = this.get('contentSize'); - var rect = geom.rectMake(0, 0, cs.width, cs.height); - return geom.rectApplyAffineTransform(rect, this.nodeToParentTransform()); + schedule: function (opts) { + if (typeof opts == 'string') { + return this.schedule({method: opts, interval: 0}); + } + + opts.interval = opts.interval || 0; + + Scheduler.get('sharedScheduler').schedule({target: this, method: opts.method, interval: opts.interval, paused: this.isRunning}); }, /** - * @private + * Unschedules a custom method + * + * @param {String|Function} method */ - _dirtyTransform: function() { - this.set('isTransformDirty', true); + unschedule: function (method) { + if (!method) { + return; + } + + if (typeof method == 'string') { + method = this[method]; + } + + Scheduler.get('sharedScheduler').unschedule({target: this, method: method}); } + }); module.exports.Node = Node; diff --git a/src/libs/cocos2d/nodes/PreloadScene.js b/src/libs/cocos2d/nodes/PreloadScene.js new file mode 100644 index 0000000..a9a58e3 --- /dev/null +++ b/src/libs/cocos2d/nodes/PreloadScene.js @@ -0,0 +1,129 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var Scene = require('./Scene').Scene, + Director = require('../Director').Director, + Label = require('./Label').Label, + ProgressBar = require('./ProgressBar').ProgressBar, + Preloader = require('../Preloader').Preloader, + RemoteResource = require('../RemoteResource').RemoteResource, + geo = require('geometry'), + util = require('util'), + events = require('events'); + +var PreloadScene = Scene.extend(/** @lends cocos.nodes.PreloadScene# */{ + progressBar: null, + label: null, + preloader: null, + isReady: false, // True when both progress bar images have loaded + emptyImage: "/__builtin__/libs/cocos2d/resources/progress-bar-empty.png", + fullImage: "/__builtin__/libs/cocos2d/resources/progress-bar-full.png", + + /** + * @memberOf cocos.nodes + * @extends cocos.nodes.Scene + * @constructs + */ + init: function (opts) { + PreloadScene.superclass.init.call(this, opts); + var size = Director.get('sharedDirector').get('winSize'); + + // Setup 'please wait' label + var label = Label.create({ + fontSize: 14, + fontName: 'Helvetica', + fontColor: '#ffffff', + string: 'Please wait...' + }); + label.set('position', new geo.Point(size.width / 2, (size.height / 2) + 32)); + this.set('label', label); + this.addChild({child: label}); + + // Setup preloader + var preloader = Preloader.create(); + this.set('preloader', preloader); + var self = this; + + // Listen for preload events + events.addListener(preloader, 'load', function (uri, preloader) { + var loaded = preloader.get('loaded'), + count = preloader.get('count'); + //console.log("Loaded: %d%% -- %d of %d -- %s", (loaded / count) * 100, loaded, count, uri); + events.trigger(self, 'load', uri, preloader); + }); + + events.addListener(preloader, 'complete', function (preloader) { + events.trigger(self, 'complete', preloader); + }); + + + // Load the images used by the progress bar + var emptyImage = resource(this.get('emptyImage')), + fullImage = resource(this.get('fullImage')); + + + var loaded = 0; + function imageLoaded() { + if (loaded == 2) { + this.isReady = true; + this.createProgressBar(); + if (this.get('isRunning')) { + preloader.load(); + } + } + } + + if (emptyImage instanceof RemoteResource) { + events.addListener(emptyImage, 'load', util.callback(this, function() { + loaded++; + imageLoaded.call(this); + })); + emptyImage.load(); + } else { + loaded++; + imageLoaded.call(this); + } + if (fullImage instanceof RemoteResource) { + events.addListener(fullImage, 'load', util.callback(this, function() { + loaded++; + imageLoaded.call(this); + })); + fullImage.load(); + } else { + loaded++; + imageLoaded.call(this); + } + + }, + + createProgressBar: function () { + var preloader = this.get('preloader'), + size = Director.get('sharedDirector').get('winSize'); + + var progressBar = ProgressBar.create({ + emptyImage: "/__builtin__/libs/cocos2d/resources/progress-bar-empty.png", + fullImage: "/__builtin__/libs/cocos2d/resources/progress-bar-full.png" + }); + + progressBar.set('position', new geo.Point(size.width / 2, size.height / 2)); + + this.set('progressBar', progressBar); + this.addChild({child: progressBar}); + + progressBar.bindTo('maxValue', preloader, 'count'); + progressBar.bindTo('value', preloader, 'loaded'); + }, + + onEnter: function () { + PreloadScene.superclass.onEnter.call(this); + var preloader = this.get('preloader'); + + // Preload everything + if (this.isReady) { + preloader.load(); + } + } +}); + +exports.PreloadScene = PreloadScene; diff --git a/src/libs/cocos2d/nodes/ProgressBar.js b/src/libs/cocos2d/nodes/ProgressBar.js new file mode 100644 index 0000000..8120cbd --- /dev/null +++ b/src/libs/cocos2d/nodes/ProgressBar.js @@ -0,0 +1,75 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var Node = require('./Node').Node, + util = require('util'), + geo = require('geometry'), + events = require('events'), + Sprite = require('./Sprite').Sprite; + +var ProgressBar = Node.extend(/** @lends cocos.nodes.ProgressBar# */{ + emptySprite: null, + fullSprite: null, + maxValue: 100, + value: 0, + + /** + * @memberOf cocos.nodes + * @extends cocos.nodes.Node + * @constructs + */ + init: function (opts) { + ProgressBar.superclass.init.call(this, opts); + var size = new geo.Size(272, 32); + this.set('contentSize', size); + + var s; + if (opts.emptyImage) { + s = Sprite.create({file: opts.emptyImage, rect: new geo.Rect(0, 0, size.width, size.height)}); + s.set('anchorPoint', new geo.Point(0, 0)); + this.set('emptySprite', s); + this.addChild({child: s}); + } + if (opts.fullImage) { + s = Sprite.create({file: opts.fullImage, rect: new geo.Rect(0, 0, 0, size.height)}); + s.set('anchorPoint', new geo.Point(0, 0)); + this.set('fullSprite', s); + this.addChild({child: s}); + } + + events.addListener(this, 'maxvalue_changed', util.callback(this, 'updateImages')); + events.addListener(this, 'value_changed', util.callback(this, 'updateImages')); + + this.updateImages(); + }, + + updateImages: function () { + var empty = this.get('emptySprite'), + full = this.get('fullSprite'), + value = this.get('value'), + size = this.get('contentSize'), + maxValue = this.get('maxValue'), + ratio = (value / maxValue); + + var diff = Math.round(size.width * ratio); + if (diff === 0) { + full.set('visible', false); + } else { + full.set('visible', true); + full.set('rect', new geo.Rect(0, 0, diff, size.height)); + full.set('contentSize', new geo.Size(diff, size.height)); + } + + if ((size.width - diff) === 0) { + empty.set('visible', false); + } else { + empty.set('visible', true); + empty.set('rect', new geo.Rect(diff, 0, size.width - diff, size.height)); + empty.set('position', new geo.Point(diff, 0)); + empty.set('contentSize', new geo.Size(size.width - diff, size.height)); + } + } +}); + +exports.ProgressBar = ProgressBar; diff --git a/src/libs/cocos2d/nodes/RenderTexture.js b/src/libs/cocos2d/nodes/RenderTexture.js index 16117b1..86789af 100644 --- a/src/libs/cocos2d/nodes/RenderTexture.js +++ b/src/libs/cocos2d/nodes/RenderTexture.js @@ -1,5 +1,9 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - event = require('event'), + evt = require('events'), Node = require('./Node').Node, geo = require('geometry'), Sprite = require('./Sprite').Sprite, @@ -21,38 +25,40 @@ var RenderTexture = Node.extend(/** @lends cocos.nodes.RenderTexture# */{ * @opt {Integer} width The width of the canvas * @opt {Integer} height The height of the canvas */ - init: function(opts) { - @super; + init: function (opts) { + RenderTexture.superclass.init.call(this, opts); - var width = opts['width'], - height = opts['height']; + var width = opts.width, + height = opts.height; - event.addListener(this, 'contentsize_changed', util.callback(this, this._resizeCanvas)); + evt.addListener(this, 'contentsize_changed', util.callback(this, this._resizeCanvas)); this.canvas = document.createElement('canvas'); this.context = this.canvas.getContext('2d'); var atlas = TextureAtlas.create({canvas: this.canvas}); - this.sprite = Sprite.create({textureAtlas: atlas, rect: {origin: ccp(0,0), size: {width: width, height: height}}}); + this.sprite = Sprite.create({textureAtlas: atlas, rect: {origin: ccp(0, 0), size: {width: width, height: height}}}); this.set('contentSize', geo.sizeMake(width, height)); this.addChild(this.sprite); this.set('anchorPoint', ccp(0, 0)); this.sprite.set('anchorPoint', ccp(0, 0)); - - }, /** * @private */ - _resizeCanvas: function() { + _resizeCanvas: function () { var size = this.get('contentSize'), canvas = this.get('canvas'); canvas.width = size.width; canvas.height = size.height; + if (FLIP_Y_AXIS) { + this.context.scale(1, -1); + this.context.translate(0, -canvas.height); + } var s = this.get('sprite'); if (s) { @@ -63,8 +69,16 @@ var RenderTexture = Node.extend(/** @lends cocos.nodes.RenderTexture# */{ /** * Clear the canvas */ - clear: function() { - this.canvas.width = this.canvas.width; + clear: function (rect) { + if (rect) { + this.context.clearRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); + } else { + this.canvas.width = this.canvas.width; + if (FLIP_Y_AXIS) { + this.context.scale(1, -1); + this.context.translate(0, -this.canvas.height); + } + } } }); diff --git a/src/libs/cocos2d/nodes/Scene.js b/src/libs/cocos2d/nodes/Scene.js index 319670f..12e5b9c 100644 --- a/src/libs/cocos2d/nodes/Scene.js +++ b/src/libs/cocos2d/nodes/Scene.js @@ -1,4 +1,9 @@ -var Node = require('./Node').Node; +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var Node = require('./Node').Node, + geo = require('geometry'); var Scene = Node.extend(/** @lends cocos.nodes.Scene */{ /** @@ -8,8 +13,15 @@ var Scene = Node.extend(/** @lends cocos.nodes.Scene */{ * @constructs * @extends cocos.nodes.Node */ - init: function() { - @super; + init: function () { + Scene.superclass.init.call(this); + + + var Director = require('../Director').Director; + var s = Director.get('sharedDirector').get('winSize'); + this.set('isRelativeAnchorPoint', false); + this.anchorPoint = new geo.Point(0.5, 0.5); + this.set('contentSize', s); } }); diff --git a/src/libs/cocos2d/nodes/Sprite.js b/src/libs/cocos2d/nodes/Sprite.js index 83cd622..6557353 100644 --- a/src/libs/cocos2d/nodes/Sprite.js +++ b/src/libs/cocos2d/nodes/Sprite.js @@ -1,5 +1,9 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - event = require('event'), + evt = require('events'), Director = require('../Director').Director, TextureAtlas = require('../TextureAtlas').TextureAtlas, Node = require('./Node').Node, @@ -28,17 +32,17 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ * @opt {String} file Path to image to use as sprite atlas * @opt {Rect} [rect] The rect in the sprite atlas image file to use as the sprite */ - init: function(opts) { - @super; + init: function (opts) { + Sprite.superclass.init.call(this, opts); opts = opts || {}; - var file = opts['file'], - textureAtlas = opts['textureAtlas'], - texture = opts['texture'], - frame = opts['frame'], - spritesheet = opts['spritesheet'], - rect = opts['rect']; + var file = opts.file, + textureAtlas = opts.textureAtlas, + texture = opts.texture, + frame = opts.frame, + spritesheet = opts.spritesheet, + rect = opts.rect; this.set('offsetPosition', ccp(0, 0)); this.set('unflippedOffsetPositionFromCenter', ccp(0, 0)); @@ -49,10 +53,10 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ rect = frame.get('rect'); } - util.each(['scale', 'scaleX', 'scaleY', 'rect', 'flipX', 'flipY'], util.callback(this, function(key) { - event.addListener(this, key.toLowerCase() + '_changed', util.callback(this, this._updateQuad)); + util.each(['scale', 'scaleX', 'scaleY', 'rect', 'flipX', 'flipY', 'contentSize'], util.callback(this, function (key) { + evt.addListener(this, key.toLowerCase() + '_changed', util.callback(this, this._updateQuad)); })); - event.addListener(this, 'textureatlas_changed', util.callback(this, this._updateTextureQuad)); + evt.addListener(this, 'textureatlas_changed', util.callback(this, this._updateTextureQuad)); if (file || texture) { textureAtlas = TextureAtlas.create({file: file, texture: texture}); @@ -64,7 +68,7 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ } if (!rect && textureAtlas) { - rect = {origin: ccp(0,0), size:{width: textureAtlas.texture.size.width, height: textureAtlas.texture.size.height}}; + rect = {origin: ccp(0, 0), size: {width: textureAtlas.texture.size.width, height: textureAtlas.texture.size.height}}; } if (rect) { @@ -87,9 +91,9 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ /** * @private */ - _updateTextureQuad: function(obj, key, texture, oldTexture) { + _updateTextureQuad: function (obj, key, texture, oldTexture) { if (oldTexture) { - oldTexture.removeQuad({quad: this.get('quad')}) + oldTexture.removeQuad({quad: this.get('quad')}); } if (texture) { @@ -101,7 +105,7 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ * @setter textureCoords * @type geometry.Rect */ - set_textureCoords: function(rect) { + set_textureCoords: function (rect) { var quad = this.get('quad'); if (!quad) { quad = { @@ -119,10 +123,10 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ * @setter textureRect * @type geometry.Rect */ - set_textureRect: function(opts) { - var rect = opts['rect'], - rotated = !!opts['rotated'], - untrimmedSize = opts['untrimmedSize'] || rect.size; + set_textureRect: function (opts) { + var rect = opts.rect, + rotated = !!opts.rotated, + untrimmedSize = opts.untrimmedSize || rect.size; this.set('contentSize', untrimmedSize); this.set('rect', util.copy(rect)); @@ -139,7 +143,7 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ relativeOffset.y = -relativeOffset.y; } - var offsetPosition = this.get('offsetPosition'); + var offsetPosition = util.copy(this.get('offsetPosition')); offsetPosition.x = relativeOffset.x + (this.get('contentSize').width - rect.size.width) / 2; offsetPosition.y = -relativeOffset.y + (this.get('contentSize').height - rect.size.height) / 2; @@ -160,7 +164,10 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ /** * @private */ - _updateQuad: function() { + _updateQuad: function () { + if (!this.get('rect')) { + return; + } if (!this.quad) { this.quad = { drawRect: geo.rectMake(0, 0, 0, 0), @@ -177,13 +184,14 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ relativeOffset.y = -relativeOffset.y; } - var offsetPosition = this.get('offsetPosition'); + var offsetPosition = util.copy(this.get('offsetPosition')); offsetPosition.x = relativeOffset.x + (this.get('contentSize').width - this.get('rect').size.width) / 2; offsetPosition.y = relativeOffset.y + (this.get('contentSize').height - this.get('rect').size.height) / 2; this.quad.textureRect = util.copy(this.rect); this.quad.drawRect.origin = util.copy(offsetPosition); this.quad.drawRect.size = util.copy(this.rect.size); + if (this.flipX) { this.quad.drawRect.size.width *= -1; this.quad.drawRect.origin.x = -this.rect.size.width; @@ -194,9 +202,9 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ } }, - updateTransform: function(ctx) { + updateTransform: function (ctx) { if (!this.useSpriteSheet) { - throw "updateTransform is only valid when Sprite is being rendered using a SpriteSheet" + throw "updateTransform is only valid when Sprite is being rendered using a SpriteSheet"; } if (!this.visible) { @@ -209,24 +217,24 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ this.quad.drawRect.origin = { x: this.position.x - this.anchorPointInPixels.x * this.scaleX, y: this.position.y - this.anchorPointInPixels.y * this.scaleY - } + }; this.quad.drawRect.size = { width: this.rect.size.width * this.scaleX, height: this.rect.size.height * this.scaleY - } + }; this.set('dirty', false); this.set('recursiveDirty', false); }, - draw: function(ctx) { + draw: function (ctx) { if (!this.quad) { return; } this.get('textureAtlas').drawQuad(ctx, this.quad); }, - isFrameDisplayed: function(frame) { + isFrameDisplayed: function (frame) { if (!this.rect || !this.textureAtlas) { return false; } @@ -238,7 +246,7 @@ var Sprite = Node.extend(/** @lends cocos.nodes.Sprite# */{ * @setter displayFrame * @type cocos.SpriteFrame */ - set_displayFrame: function(frame) { + set_displayFrame: function (frame) { if (!frame) { delete this.quad; return; diff --git a/src/libs/cocos2d/nodes/TMXLayer.js b/src/libs/cocos2d/nodes/TMXLayer.js index 39bfc7b..87bddb2 100644 --- a/src/libs/cocos2d/nodes/TMXLayer.js +++ b/src/libs/cocos2d/nodes/TMXLayer.js @@ -1,3 +1,7 @@ +/*globals module exports resource require BObject BArray FLIP_Y_AXIS*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), SpriteBatchNode = require('./BatchNode').SpriteBatchNode, Sprite = require('./Sprite').Sprite, @@ -28,10 +32,10 @@ var TMXLayer = SpriteBatchNode.extend(/** @lends cocos.nodes.TMXLayer# */{ * @opt {cocos.TMXLayerInfo} layerInfo * @opt {cocos.TMXMapInfo} mapInfo */ - init: function(opts) { - var tilesetInfo = opts['tilesetInfo'], - layerInfo = opts['layerInfo'], - mapInfo = opts['mapInfo']; + init: function (opts) { + var tilesetInfo = opts.tilesetInfo, + layerInfo = opts.layerInfo, + mapInfo = opts.mapInfo; var size = layerInfo.get('layerSize'), totalNumberOfTiles = size.width * size.height; @@ -41,9 +45,9 @@ var TMXLayer = SpriteBatchNode.extend(/** @lends cocos.nodes.TMXLayer# */{ tex = tilesetInfo.sourceImage; } - @super({file: tex}); + TMXLayer.superclass.init.call(this, {file: tex}); - this.set('anchorPoint', ccp(0, 0)); + this.set('anchorPoint', ccp(0, 0)); this.layerName = layerInfo.get('name'); this.layerSize = layerInfo.get('layerSize'); @@ -60,10 +64,10 @@ var TMXLayer = SpriteBatchNode.extend(/** @lends cocos.nodes.TMXLayer# */{ var offset = this.calculateLayerOffset(layerInfo.get('offset')); this.set('position', offset); - this.set('contentSize', geo.sizeMake(this.layerSize.width * this.mapTileSize.width, this.layerSize.height * this.mapTileSize.height)); + this.set('contentSize', geo.sizeMake(this.layerSize.width * this.mapTileSize.width, (this.layerSize.height * (this.mapTileSize.height - 1)) + this.tileset.tileSize.height)); }, - calculateLayerOffset: function(pos) { + calculateLayerOffset: function (pos) { var ret = ccp(0, 0); switch (this.layerOrientation) { @@ -81,18 +85,18 @@ var TMXLayer = SpriteBatchNode.extend(/** @lends cocos.nodes.TMXLayer# */{ return ret; }, - setupTiles: function() { + setupTiles: function () { this.tileset.bindTo('imageSize', this.get('texture'), 'contentSize'); - for (var y=0; y < this.layerSize.height; y++) { - for (var x=0; x < this.layerSize.width; x++) { + for (var y = 0; y < this.layerSize.height; y++) { + for (var x = 0; x < this.layerSize.width; x++) { var pos = x + this.layerSize.width * y, gid = this.tiles[pos]; - if (gid != 0) { - this.appendTile({gid:gid, position:ccp(x,y)}); + if (gid !== 0) { + this.appendTile({gid: gid, position: ccp(x, y)}); // Optimization: update min and max GID rendered by the layer this.minGID = Math.min(gid, this.minGID); @@ -101,9 +105,9 @@ var TMXLayer = SpriteBatchNode.extend(/** @lends cocos.nodes.TMXLayer# */{ } } }, - appendTile: function(opts) { - var gid = opts['gid'], - pos = opts['position']; + appendTile: function (opts) { + var gid = opts.gid, + pos = opts.position; var z = pos.x + pos.y * this.layerSize.width; @@ -115,39 +119,86 @@ var TMXLayer = SpriteBatchNode.extend(/** @lends cocos.nodes.TMXLayer# */{ this.addChild({child: tile, z: 0, tag: z}); }, - positionAt: function(pos) { - var ret = ccp(0, 0); - + positionAt: function (pos) { switch (this.layerOrientation) { case TMXOrientationOrtho: - ret = this.positionForOrthoAt(pos); - break; + return this.positionForOrthoAt(pos); case TMXOrientationIso: - // TODO - break; + return this.positionForIsoAt(pos); + /* case TMXOrientationHex: // TODO - break; + */ + default: + return ccp(0, 0); } - - return ret; }, - positionForOrthoAt: function(pos) { + positionForOrthoAt: function (pos) { var overlap = this.mapTileSize.height - this.tileset.tileSize.height; var x = Math.floor(pos.x * this.mapTileSize.width + 0.49); - var y = Math.floor(pos.y * this.mapTileSize.height + 0.49) + overlap; - return ccp(x,y); + var y; + if (FLIP_Y_AXIS) { + y = Math.floor((this.get('layerSize').height - pos.y - 1) * this.mapTileSize.height + 0.49); + } else { + y = Math.floor(pos.y * this.mapTileSize.height + 0.49) + overlap; + } + return ccp(x, y); + }, + + positionForIsoAt: function (pos) { + var mapTileSize = this.get('mapTileSize'), + layerSize = this.get('layerSize'); + + if (FLIP_Y_AXIS) { + return ccp( + mapTileSize.width / 2 * (layerSize.width + pos.x - pos.y - 1), + mapTileSize.height / 2 * ((layerSize.height * 2 - pos.x - pos.y) - 2) + ); + } else { + throw "Isometric tiles without FLIP_Y_AXIS is currently unsupported"; + } }, - tileGID: function(pos) { + /** + * Get the tile at a specifix tile coordinate + * + * @param {geometry.Point} pos Position of tile to get in tile coordinates (not pixels) + * @returns {cocos.nodes.Sprite} The tile + */ + tileAt: function (pos) { + var layerSize = this.get('layerSize'), + tiles = this.get('tiles'); + + if (pos.x < 0 || pos.y < 0 || pos.x >= layerSize.width || pos.y >= layerSize.height) { + throw "TMX Layer: Invalid position"; + } + + var tile, + gid = this.tileGIDAt(pos); + + // if GID is 0 then no tile exists at that point + if (gid) { + var z = pos.x + pos.y * layerSize.width; + tile = this.getChild({tag: z}); + } + + return tile; + }, + + + tileGID: function (pos) { var tilesPerRow = this.get('layerSize').width, tilePos = pos.x + (pos.y * tilesPerRow); return this.tiles[tilePos]; }, - removeTile: function(pos) { + tileGIDAt: function (pos) { + return this.tileGID(pos); + }, + + removeTile: function (pos) { var gid = this.tileGID(pos); - if (gid == 0) { + if (gid === 0) { // Tile is already blank return; } diff --git a/src/libs/cocos2d/nodes/TMXTiledMap.js b/src/libs/cocos2d/nodes/TMXTiledMap.js index 51bfd0e..152d107 100644 --- a/src/libs/cocos2d/nodes/TMXTiledMap.js +++ b/src/libs/cocos2d/nodes/TMXTiledMap.js @@ -1,5 +1,8 @@ +/*globals module exports resource require BObject BArray console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), - console = require('system').console, geo = require('geometry'), ccp = geo.ccp, Node = require('./Node').Node, @@ -26,12 +29,12 @@ var TMXTiledMap = Node.extend(/** @lends cocos.nodes.TMXTiledMap# */{ * * @opt {String} file The file path of the TMX map to load */ - init: function(opts) { - @super; + init: function (opts) { + TMXTiledMap.superclass.init.call(this, opts); this.set('anchorPoint', ccp(0, 0)); - var mapInfo = TMXMapInfo.create(opts['file']); + var mapInfo = TMXMapInfo.create(opts.file); this.mapSize = mapInfo.get('mapSize'); this.tileSize = mapInfo.get('tileSize'); @@ -42,10 +45,10 @@ var TMXTiledMap = Node.extend(/** @lends cocos.nodes.TMXTiledMap# */{ // Add layers to map var idx = 0; - util.each(mapInfo.layers, util.callback(this, function(layerInfo) { + util.each(mapInfo.layers, util.callback(this, function (layerInfo) { if (layerInfo.get('visible')) { var child = this.parseLayer({layerInfo: layerInfo, mapInfo: mapInfo}); - this.addChild({child:child, z:idx, tag:idx}); + this.addChild({child: child, z: idx, tag: idx}); var childSize = child.get('contentSize'); var currentSize = this.get('contentSize'); @@ -58,38 +61,87 @@ var TMXTiledMap = Node.extend(/** @lends cocos.nodes.TMXTiledMap# */{ })); }, - parseLayer: function(opts) { + parseLayer: function (opts) { var tileset = this.tilesetForLayer(opts); - var layer = TMXLayer.create({tilesetInfo: tileset, layerInfo: opts['layerInfo'], mapInfo: opts['mapInfo']}); + var layer = TMXLayer.create({tilesetInfo: tileset, layerInfo: opts.layerInfo, mapInfo: opts.mapInfo}); layer.setupTiles(); return layer; }, - tilesetForLayer: function(opts) { - var layerInfo = opts['layerInfo'], - mapInfo = opts['mapInfo'], + tilesetForLayer: function (opts) { + var layerInfo = opts.layerInfo, + mapInfo = opts.mapInfo, size = layerInfo.get('layerSize'); // Reverse loop - for (var i = mapInfo.tilesets.length -1; i >= 0; i--) { - var tileset = mapInfo.tilesets[i]; + var tileset; + for (var i = mapInfo.tilesets.length - 1; i >= 0; i--) { + tileset = mapInfo.tilesets[i]; - for (var y=0; y < size.height; y++ ) { - for (var x=0; x < size.width; x++ ) { + for (var y = 0; y < size.height; y++) { + for (var x = 0; x < size.width; x++) { var pos = x + size.width * y, gid = layerInfo.tiles[pos]; - if (gid != 0 && gid >= tileset.firstGID) { + if (gid !== 0 && gid >= tileset.firstGID) { return tileset; } } // for (var x } // for (var y } // for (var i - console.warn("cocos2d: Warning: TMX Layer '%s' has no tiles", layerInfo.name) + //console.log("cocos2d: Warning: TMX Layer '%s' has no tiles", layerInfo.name); return tileset; + }, + + /** + * Get a layer + * + * @opt {String} name The name of the layer to get + * @returns {cocos.nodes.TMXLayer} The layer requested + */ + getLayer: function (opts) { + var layerName = opts.name, + layer = null; + + this.get('children').forEach(function (item) { + if (item instanceof TMXLayer && item.layerName == layerName) { + layer = item; + } + }); + if (layer !== null) { + return layer; + } + }, + + /** + * Return the ObjectGroup for the secific group + * + * @opt {String} name The object group name + * @returns {cocos.TMXObjectGroup} The object group + */ + getObjectGroup: function (opts) { + var objectGroupName = opts.name, + objectGroup = null; + + this.objectGroups.forEach(function (item) { + if (item.name == objectGroupName) { + objectGroup = item; + } + }); + if (objectGroup !== null) { + return objectGroup; + } + }, + + /** + * @deprected Since v0.2. You should now use cocos.TMXTiledMap#getObjectGroup. + */ + objectGroupNamed: function (opts) { + console.warn('TMXTiledMap#objectGroupNamed is deprected. Use TMXTiledMap#getObjectGroup instread'); + return this.getObjectGroup(opts); } }); diff --git a/src/libs/cocos2d/nodes/Transition.js b/src/libs/cocos2d/nodes/Transition.js new file mode 100644 index 0000000..900eb36 --- /dev/null +++ b/src/libs/cocos2d/nodes/Transition.js @@ -0,0 +1,398 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var geo = require('geometry'), + util = require('util'), + actions = require('../actions'), + Scene = require('./Scene').Scene, + Director = require('../Director').Director, + EventDispatcher = require('../EventDispatcher').EventDispatcher, + Scheduler = require('../Scheduler').Scheduler; + +/** Orientation Type used by some transitions + */ +var tOrientation = { + kOrientationLeftOver: 0, + kOrientationRightOver: 1, + kOrientationUpOver: 0, + kOrientationDownOver: 1 +}; + +/** + */ +var TransitionScene = Scene.extend(/** @lends cocos.nodes.TransitionScene */{ + /** + * Incoming scene + * @type {cocos.nodes.Scene} + */ + inScene: null, + + /** + * Outgoing (current) scene + * @type {cocos.nodes.Scene} + */ + outScene: null, + + /** + * transition duration + * @type Float + */ + duration: null, + + inSceneOnTop: null, + sendCleanupToScene: null, + + /** + * @class Base class for Transition scenes + * @memberOf cocos.nodes + * @extends cocos.nodes.Scene + * @constructs + * + * @opt {Float} duration How long the transition should last + * @opt {cocos.nodes.Scene} scene Income scene + */ + init: function (opts) { + TransitionScene.superclass.init.call(this, opts); + + this.set('duration', opts.duration); + if (!opts.scene) { + throw "TransitionScene requires scene property"; + } + this.set('inScene', opts.scene); + this.set('outScene', Director.get('sharedDirector')._runningScene); + + if (this.inScene == this.outScene) { + throw "Incoming scene must be different from the outgoing scene"; + } + EventDispatcher.get('sharedDispatcher').set('dispatchEvents', false); + this.sceneOrder(); + }, + + /** + * Called after the transition finishes + */ + finish: function () { + var is = this.get('inScene'), + os = this.get('outScene'); + + /* clean up */ + is.set('visible', true); + is.set('position', geo.PointZero()); + is.set('scale', 1.0); + is.set('rotation', 0); + + os.set('visible', false); + os.set('position', geo.PointZero()); + os.set('scale', 1.0); + os.set('rotation', 0); + + Scheduler.get('sharedScheduler').schedule({ + target: this, + method: this.setNewScene, + interval: 0 + }); + }, + + /** + * Used by some transitions to hide the outer scene + */ + hideOutShowIn: function () { + this.get('inScene').set('visible', true); + this.get('outScene').set('visible', false); + }, + + setNewScene: function (dt) { + var dir = Director.get('sharedDirector'); + + this.unscheduleSelector(this.setNewScene); + // Save 'send cleanup to scene' + // Not sure if it's cool to be accessing all these Director privates like this... + this.set('sendCleanupToScene', dir._sendCleanupToScene); + + dir.replaceScene(this.get('inScene')); + + // enable events while transitions + EventDispatcher.get('sharedDispatcher').set('dispatchEvents', true); + + // issue #267 + this.get('outScene').set('visible', true); + }, + + sceneOrder: function () { + this.set('inSceneOnTop', true); + }, + + draw: function (context, rect) { + if (this.get('inSceneOnTop')) { + this.get('outScene').visit(context, rect); + this.get('inScene').visit(context, rect); + } else { + this.get('inScene').visit(context, rect); + this.get('outScene').visit(context, rect); + } + }, + + onEnter: function () { + TransitionScene.superclass.onEnter.call(this); + this.get('inScene').onEnter(); + // outScene_ should not receive the onEnter callback + }, + + onExit: function () { + TransitionScene.superclass.onExit.call(this); + this.get('outScene').onExit(); + // inScene_ should not receive the onExit callback + // only the onEnterTransitionDidFinish + if (this.get('inScene').hasOwnProperty('onEnterTransitionDidFinish')) { + this.get('inScene').onEnterTransitionDidFinish(); + } + }, + + cleanup: function () { + TransitionScene.superclass.cleanup.call(this); + + if (this.get('sendCleanupToScene')) { + this.get('outScene').cleanup(); + } + } +}); + +/** + * @class Rotate and zoom out the outgoing scene, and then rotate and zoom in the incoming + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionScene + */ +var TransitionRotoZoom = TransitionScene.extend(/** @lends cocos.nodes.TransitionRotoZoom */{ + onEnter: function() { + TransitionRotoZoom.superclass.onEnter.call(this); + + var dur = this.get('duration'); + this.get('inScene').set('scale', 0.001); + this.get('outScene').set('scale', 1.0); + + this.get('inScene').set('anchorPoint', geo.ccp(0.5, 0.5)); + this.get('outScene').set('anchorPoint', geo.ccp(0.5, 0.5)); + + var outzoom = [ + actions.Spawn.initWithActions({actions: [ + actions.ScaleBy.create({scale: 0.001, duration: dur/2}), + actions.RotateBy.create({angle: 360*2, duration: dur/2}) + ]}), + actions.DelayTime.create({duration: dur/2})]; + + // Can't nest sequences or reverse them very easily, so incoming scene actions must be put + // together manually for now... + var inzoom = [ + actions.DelayTime.create({duration: dur/2}), + + actions.Spawn.initWithActions({actions: [ + actions.ScaleTo.create({scale: 1.0, duration: dur/2}), + actions.RotateBy.create({angle: -360*2, duration: dur/2}) + ]}), + actions.CallFunc.create({ + target: this, + method: this.finish + }) + ]; + + // Sequence init() copies actions + this.get('outScene').runAction(actions.Sequence.create({actions: outzoom})); + this.get('inScene').runAction(actions.Sequence.create({actions: inzoom})); + } +}); + +/** + * @class Move in from to the left the incoming scene. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionScene + */ +var TransitionMoveInL = TransitionScene.extend(/** @lends cocos.nodes.TransitionMoveInL */{ + onEnter: function () { + TransitionMoveInL.superclass.onEnter.call(this); + + this.initScenes(); + + this.get('inScene').runAction(actions.Sequence.create({actions: [ + this.action(), + actions.CallFunc.create({ + target: this, + method: this.finish + })] + })); + }, + + action: function () { + return actions.MoveTo.create({ + position: geo.ccp(0, 0), + duration: this.get('duration') + }); + }, + + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(-s.width, 0)); + } +}); + +/** + * @class Move in from to the right the incoming scene. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionMoveInL + */ +var TransitionMoveInR = TransitionMoveInL.extend(/** @lends cocos.nodes.TransitionMoveInR */{ + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(s.width, 0)); + } +}); + +/** + * @class Move the incoming scene in from the top. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionMoveInL + */ +var TransitionMoveInT = TransitionMoveInL.extend(/** @lends cocos.nodes.TransitionMoveInT */{ + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(0, s.height)); + } +}); + +/** + * @class Move the incoming scene in from the bottom. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionMoveInL + */ +var TransitionMoveInB = TransitionMoveInL.extend(/** @lends cocos.nodes.TransitionMoveInB */{ + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(0, -s.height)); + } +}); + +/** + * @class Slide in the incoming scene from the left. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionScene + */ +var TransitionSlideInL = TransitionScene.extend(/** @lends cocos.nodes.TransitionSlideInL */{ + onEnter: function () { + TransitionSlideInL.superclass.onEnter.call(this); + + this.initScenes(); + + var movein = this.action(); + var moveout = this.action(); + var outAction = actions.Sequence.create({ + actions: [ + moveout, + actions.CallFunc.create({ + target: this, + method: this.finish + })] + }); + this.get('inScene').runAction(movein); + this.get('outScene').runAction(outAction); + }, + + sceneOrder: function () { + this.set('inSceneOnTop', false); + }, + + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(-s.width, 0)); + }, + + action: function () { + var s = Director.get('sharedDirector').get('winSize'); + return actions.MoveBy.create({ + position: geo.ccp(s.width, 0), + duration: this.get('duration') + }); + } +}); + +/** + * @class Slide in the incoming scene from the right. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionSlideInL + */ +var TransitionSlideInR = TransitionSlideInL.extend(/** @lends cocos.nodes.TransitionSlideInR */{ + sceneOrder: function () { + this.set('inSceneOnTop', true); + }, + + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(s.width, 0)); + }, + + action: function () { + var s = Director.get('sharedDirector').get('winSize'); + return actions.MoveBy.create({ + position: geo.ccp(-s.width, 0), + duration: this.get('duration') + }); + } +}); + +/** + * @class Slide in the incoming scene from the top. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionSlideInL + */ +var TransitionSlideInT = TransitionSlideInL.extend(/** @lends cocos.nodes.TransitionSlideInT */{ + sceneOrder: function () { + this.set('inSceneOnTop', false); + }, + + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(0, s.height)); + }, + + action: function () { + var s = Director.get('sharedDirector').get('winSize'); + return actions.MoveBy.create({ + position: geo.ccp(0, -s.height), + duration: this.get('duration') + }); + } +}); + +/** + * @class Slide in the incoming scene from the bottom. + * @memberOf cocos.nodes + * @extends cocos.nodes.TransitionSlideInL + */ +var TransitionSlideInB = TransitionSlideInL.extend(/** @lends cocos.nodes.TransitionSlideInB */{ + sceneOrder: function () { + this.set('inSceneOnTop', true); + }, + + initScenes: function () { + var s = Director.get('sharedDirector').get('winSize'); + this.get('inScene').set('position', geo.ccp(0, -s.height)); + }, + + action: function () { + var s = Director.get('sharedDirector').get('winSize'); + return actions.MoveBy.create({ + position: geo.ccp(0, s.height), + duration: this.get('duration') + }); + } +}); + +exports.TransitionScene = TransitionScene; +exports.TransitionRotoZoom = TransitionRotoZoom; +exports.TransitionMoveInL = TransitionMoveInL; +exports.TransitionMoveInR = TransitionMoveInR; +exports.TransitionMoveInT = TransitionMoveInT; +exports.TransitionMoveInB = TransitionMoveInB; +exports.TransitionSlideInL = TransitionSlideInL; +exports.TransitionSlideInR = TransitionSlideInR; +exports.TransitionSlideInT = TransitionSlideInT; +exports.TransitionSlideInB = TransitionSlideInB; diff --git a/src/libs/cocos2d/nodes/index.js b/src/libs/cocos2d/nodes/index.js index fabe16f..fcc4d56 100644 --- a/src/libs/cocos2d/nodes/index.js +++ b/src/libs/cocos2d/nodes/index.js @@ -1,7 +1,11 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'), path = require('path'); -var modules = 'Node Layer Scene Label Sprite TMXTiledMap BatchNode RenderTexture Menu MenuItem'.w() +var modules = 'AtlasNode LabelAtlas ProgressBar PreloadScene Node Layer Scene Label Sprite TMXTiledMap BatchNode RenderTexture Menu MenuItem Transition'.w(); /** * @memberOf cocos @@ -9,7 +13,7 @@ var modules = 'Node Layer Scene Label Sprite TMXTiledMap BatchNode RenderTexture */ var nodes = {}; -util.each(modules, function(mod, i) { +util.each(modules, function (mod, i) { util.extend(nodes, require('./' + mod)); }); diff --git a/src/libs/cocos2d/resources/progress-bar-empty.png b/src/libs/cocos2d/resources/progress-bar-empty.png new file mode 100644 index 0000000..27bb5a9 Binary files /dev/null and b/src/libs/cocos2d/resources/progress-bar-empty.png differ diff --git a/src/libs/cocos2d/resources/progress-bar-full.png b/src/libs/cocos2d/resources/progress-bar-full.png new file mode 100644 index 0000000..306f398 Binary files /dev/null and b/src/libs/cocos2d/resources/progress-bar-full.png differ diff --git a/src/libs/geometry.js b/src/libs/geometry.js index debd991..665e4b6 100644 --- a/src/libs/geometry.js +++ b/src/libs/geometry.js @@ -1,7 +1,13 @@ +/*globals module exports resource require BObject BArray*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var util = require('util'); -var RE_PAIR = /{\s*([\d.-]+)\s*,\s*([\d.-]+)\s*}/, - RE_DOUBLE_PAIR = /{\s*({[\s\d,.-]+})\s*,\s*({[\s\d,.-]+})\s*}/; +var RE_PAIR = /\{\s*([\d.\-]+)\s*,\s*([\d.\-]+)\s*\}/, + RE_DOUBLE_PAIR = /\{\s*(\{[\s\d,.\-]+\})\s*,\s*(\{[\s\d,.\-]+\})\s*\}/; + +Math.PI_2 = 1.57079632679489661923132169163975144 /* pi/2 */ /** @namespace */ var geometry = { @@ -12,7 +18,7 @@ var geometry = { * @param {Float} x X value * @param {Float} y Y value */ - Point: function(x, y) { + Point: function (x, y) { /** * X coordinate * @type Float @@ -33,7 +39,7 @@ var geometry = { * @param {Float} w Width * @param {Float} h Height */ - Size: function(w, h) { + Size: function (w, h) { /** * Width * @type Float @@ -56,7 +62,7 @@ var geometry = { * @param {Float} w Width * @param {Float} h Height */ - Rect: function(x, y, w, h) { + Rect: function (x, y, w, h) { /** * Coordinate in 2D space * @type {geometry.Point} @@ -70,6 +76,40 @@ var geometry = { this.size = new geometry.Size(w, h); }, + /** + * @class + * Transform matrix + * + * @param {Float} a + * @param {Float} b + * @param {Float} c + * @param {Float} d + * @param {Float} tx + * @param {Float} ty + */ + TransformMatrix: function (a, b, c, d, tx, ty) { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.tx = tx; + this.ty = ty; + }, + + /** + * @class + * Bezier curve control object + * + * @param {geometry.Point} controlPoint1 + * @param {geometry.Point} controlPoint2 + * @param {geometry.Point} endPoint + */ + BezierConfig: function(p1, p2, ep) { + this.controlPoint1 = util.copy(p1); + this.controlPoint2 = util.copy(p2); + this.endPosition = util.copy(ep); + }, + /** * Creates a geometry.Point instance * @@ -77,7 +117,7 @@ var geometry = { * @param {Float} y Y coordinate * @returns {geometry.Point} */ - ccp: function(x, y) { + ccp: function (x, y) { return module.exports.pointMake(x, y); }, @@ -88,7 +128,7 @@ var geometry = { * @param {geometry.Point} p2 Second point * @returns {geometry.Point} New point */ - ccpAdd: function(p1, p2) { + ccpAdd: function (p1, p2) { return geometry.ccp(p1.x + p2.x, p1.y + p2.y); }, @@ -99,7 +139,7 @@ var geometry = { * @param {geometry.Point} p2 Second point * @returns {geometry.Point} New point */ - ccpSub: function(p1, p2) { + ccpSub: function (p1, p2) { return geometry.ccp(p1.x - p2.x, p1.y - p2.y); }, @@ -110,7 +150,7 @@ var geometry = { * @param {geometry.Point} p2 Second point * @returns {geometry.Point} New point */ - ccpMult: function(p1, p2) { + ccpMult: function (p1, p2) { return geometry.ccp(p1.x * p2.x, p1.y * p2.y); }, @@ -121,7 +161,7 @@ var geometry = { * @param {geometry.Point} p Point to invert * @returns {geometry.Point} New point */ - ccpNeg: function(p) { + ccpNeg: function (p) { return geometry.ccp(-p.x, -p.y); }, @@ -131,7 +171,7 @@ var geometry = { * @param {geometry.Point} p Point to round * @returns {geometry.Point} New point */ - ccpRound: function(p) { + ccpRound: function (p) { return geometry.ccp(Math.round(p.x), Math.round(p.y)); }, @@ -141,7 +181,7 @@ var geometry = { * @param {geometry.Point} p Point to round * @returns {geometry.Point} New point */ - ccpCeil: function(p) { + ccpCeil: function (p) { return geometry.ccp(Math.ceil(p.x), Math.ceil(p.y)); }, @@ -151,7 +191,7 @@ var geometry = { * @param {geometry.Point} p Point to round * @returns {geometry.Point} New point */ - ccpFloor: function(p) { + ccpFloor: function (p) { return geometry.ccp(Math.floor(p.x), Math.floor(p.y)); }, @@ -160,21 +200,21 @@ var geometry = { * * @returns {geometry.Point} New point at 0x0 */ - PointZero: function() { - return geometry.ccp(0,0); + PointZero: function () { + return geometry.ccp(0, 0); }, /** * @returns {geometry.Rect} */ - rectMake: function(x, y, w, h) { + rectMake: function (x, y, w, h) { return new geometry.Rect(x, y, w, h); }, /** * @returns {geometry.Rect} */ - rectFromString: function(str) { + rectFromString: function (str) { var matches = str.match(RE_DOUBLE_PAIR), p = geometry.pointFromString(matches[1]), s = geometry.sizeFromString(matches[2]); @@ -185,14 +225,14 @@ var geometry = { /** * @returns {geometry.Size} */ - sizeMake: function(w, h) { + sizeMake: function (w, h) { return new geometry.Size(w, h); }, /** * @returns {geometry.Size} */ - sizeFromString: function(str) { + sizeFromString: function (str) { var matches = str.match(RE_PAIR), w = parseFloat(matches[1]), h = parseFloat(matches[2]); @@ -203,14 +243,14 @@ var geometry = { /** * @returns {geometry.Point} */ - pointMake: function(x, y) { + pointMake: function (x, y) { return new geometry.Point(x, y); }, /** * @returns {geometry.Point} */ - pointFromString: function(str) { + pointFromString: function (str) { var matches = str.match(RE_PAIR), x = parseFloat(matches[1]), y = parseFloat(matches[2]); @@ -221,101 +261,151 @@ var geometry = { /** * @returns {Boolean} */ - rectContainsPoint: function(r, p) { - return ((p.x >= r.origin.x && p.x <= r.origin.x + r.size.width) - && (p.y >= r.origin.y && p.y <= r.origin.y + r.size.height)); + rectContainsPoint: function (r, p) { + return ((p.x >= r.origin.x && p.x <= r.origin.x + r.size.width) && + (p.y >= r.origin.y && p.y <= r.origin.y + r.size.height)); + }, + + /** + * Returns the smallest rectangle that contains the two source rectangles. + * + * @param {geometry.Rect} r1 + * @param {geometry.Rect} r2 + * @returns {geometry.Rect} + */ + rectUnion: function (r1, r2) { + var rect = new geometry.Rect(0, 0, 0, 0); + + rect.origin.x = Math.min(r1.origin.x, r2.origin.x); + rect.origin.y = Math.min(r1.origin.y, r2.origin.y); + rect.size.width = Math.max(r1.origin.x + r1.size.width, r2.origin.x + r2.size.width) - rect.origin.x; + rect.size.height = Math.max(r1.origin.y + r1.size.height, r2.origin.y + r2.size.height) - rect.origin.y; + + return rect; }, /** * @returns {Boolean} */ - rectOverlapsRect: function(r1, r2) { - if (r1.origin.x + r1.size.width < r2.origin.x) - return false - if (r2.origin.x + r2.size.width < r1.origin.x) - return false - if (r1.origin.y + r1.size.height < r2.origin.y) - return false - if (r2.origin.y + r2.size.height < r1.origin.y) - return false + rectOverlapsRect: function (r1, r2) { + if (r1.origin.x + r1.size.width < r2.origin.x) { + return false; + } + if (r2.origin.x + r2.size.width < r1.origin.x) { + return false; + } + if (r1.origin.y + r1.size.height < r2.origin.y) { + return false; + } + if (r2.origin.y + r2.size.height < r1.origin.y) { + return false; + } return true; }, + /** + * Returns the overlapping portion of 2 rectangles + * + * @param {geometry.Rect} lhsRect First rectangle + * @param {geometry.Rect} rhsRect Second rectangle + * @returns {geometry.Rect} The overlapping portion of the 2 rectangles + */ + rectIntersection: function (lhsRect, rhsRect) { + + var intersection = new geometry.Rect( + Math.max(geometry.rectGetMinX(lhsRect), geometry.rectGetMinX(rhsRect)), + Math.max(geometry.rectGetMinY(lhsRect), geometry.rectGetMinY(rhsRect)), + 0, + 0 + ); + + intersection.size.width = Math.min(geometry.rectGetMaxX(lhsRect), geometry.rectGetMaxX(rhsRect)) - geometry.rectGetMinX(intersection); + intersection.size.height = Math.min(geometry.rectGetMaxY(lhsRect), geometry.rectGetMaxY(rhsRect)) - geometry.rectGetMinY(intersection); + + return intersection; + }, + /** * @returns {Boolean} */ - pointEqualToPoint: function(point1, point2) { + pointEqualToPoint: function (point1, point2) { return (point1.x == point2.x && point1.y == point2.y); }, /** * @returns {Boolean} */ - sizeEqualToSize: function(size1, size2) { + sizeEqualToSize: function (size1, size2) { return (size1.width == size2.width && size1.height == size2.height); }, /** * @returns {Boolean} */ - rectEqualToRect: function(rect1, rect2) { + rectEqualToRect: function (rect1, rect2) { return (module.exports.sizeEqualToSize(rect1.size, rect2.size) && module.exports.pointEqualToPoint(rect1.origin, rect2.origin)); }, /** * @returns {Float} */ - rectGetMinX: function(rect) { + rectGetMinX: function (rect) { return rect.origin.x; }, /** * @returns {Float} */ - rectGetMinY: function(rect) { + rectGetMinY: function (rect) { return rect.origin.y; }, /** * @returns {Float} */ - rectGetMaxX: function(rect) { + rectGetMaxX: function (rect) { return rect.origin.x + rect.size.width; }, /** * @returns {Float} */ - rectGetMaxY: function(rect) { + rectGetMaxY: function (rect) { return rect.origin.y + rect.size.height; }, - boundingRectMake: function(p1, p2, p3, p4) { - var minX = Math.min(p1.x, Math.min(p2.x, Math.min(p3.x, p4.x))); - var minY = Math.min(p1.y, Math.min(p2.y, Math.min(p3.y, p4.y))); - var maxX = Math.max(p1.x, Math.max(p2.x, Math.max(p3.x, p4.x))); - var maxY = Math.max(p1.y, Math.max(p2.y, Math.max(p3.y, p4.y))); + boundingRectMake: function (p1, p2, p3, p4) { + var minX = Math.min(p1.x, p2.x, p3.x, p4.x); + var minY = Math.min(p1.y, p2.y, p3.y, p4.y); + var maxX = Math.max(p1.x, p2.x, p3.x, p4.x); + var maxY = Math.max(p1.y, p2.y, p3.y, p4.y); - return geometry.rectMake(minX, minY, (maxX - minX), (maxY - minY)); + return new geometry.Rect(minX, minY, (maxX - minX), (maxY - minY)); }, /** * @returns {geometry.Point} */ - pointApplyAffineTransform: function(p, trans) { - var newPoint = geometry.ccp(0, 0); - - newPoint.x = p.x * trans[0][0] + p.y * trans[1][0] + trans[2][0]; - newPoint.y = p.x * trans[0][1] + p.y * trans[1][1] + trans[2][1]; + pointApplyAffineTransform: function (point, t) { + + /* + aPoint.x * aTransform.a + aPoint.y * aTransform.c + aTransform.tx, + aPoint.x * aTransform.b + aPoint.y * aTransform.d + aTransform.ty + */ + + return new geometry.Point(t.a * point.x + t.c * point.y + t.tx, t.b * point.x + t.d * point.y + t.ty); - return newPoint; }, /** - * @returns {geometry.Rect} + * Apply a transform matrix to a rectangle + * + * @param {geometry.Rect} rect Rectangle to transform + * @param {geometry.TransformMatrix} trans TransformMatrix to apply to rectangle + * @returns {geometry.Rect} A new transformed rectangle */ - rectApplyAffineTransform: function(rect, trans) { + rectApplyAffineTransform: function (rect, trans) { var p1 = geometry.ccp(geometry.rectGetMinX(rect), geometry.rectGetMinY(rect)); var p2 = geometry.ccp(geometry.rectGetMaxX(rect), geometry.rectGetMinY(rect)); @@ -331,162 +421,112 @@ var geometry = { }, /** - * @returns {Float} + * Inverts a transform matrix + * + * @param {geometry.TransformMatrix} trans TransformMatrix to invert + * @returns {geometry.TransformMatrix} New transform matrix */ - affineTransformDeterminant: function(trans) { - var det = 1, - t = util.copy(trans); - - var k, i, j, q, tkk; - for (k = 0; k < 3; k++) { - tkk = t[k][k]; + affineTransformInvert: function (trans) { + var determinant = 1 / (trans.a * trans.d - trans.b * trans.c); - if (tkk == 0) { - i = k; - while (t[i][k] == 0) { - if (i++ > 3) { - return 0; - } - } - - // Swap t[i] and t[k] - t[i] = t[i] + t[k]; t[k] = t[i] - t[k]; t[i] = t[i] - t[k]; - - tkk = t[k][k]; - - det *= -1; - } - - for (i = k+1; i < 3; i++) { - q = t[i][k] / tkk; - for (j = k+1; j < 3; j++) { - t[i][j] -= t[k][j] * q - } - } - - det *= tkk; - } - - return det; + return new geometry.TransformMatrix( + determinant * trans.d, + -determinant * trans.b, + -determinant * trans.c, + determinant * trans.a, + determinant * (trans.c * trans.ty - trans.d * trans.tx), + determinant * (trans.b * trans.tx - trans.a * trans.ty) + ); }, /** - * @returns {Float[]} + * Multiply 2 transform matrices together + * @param {geometry.TransformMatrix} lhs Left matrix + * @param {geometry.TransformMatrix} rhs Right matrix + * @returns {geometry.TransformMatrix} New transform matrix */ - affineTransformInvert: function(trans) { - var newTrans = module.exports.affineTransformIdentity(); - - var t = util.copy(trans); - - var k, i, j, q, tkk; - for (k = 0; k < 3; k++) { - tkk = t[k][k]; - - if (tkk == 0) { - i = k; - do { - if (i++ > 3) { - throw "Matrix not regular size"; - } - } while (t[i][k] == 0); - - // Swap t[i] and t[k] - t[i] = t[i] + t[k]; - t[k] = t[i] - t[k]; - t[i] = t[i] - t[k]; - newTrans[i] = newTrans[i] + newTrans[k]; - newTrans[k] = newTrans[i] - newTrans[k]; - newTrans[i] = newTrans[i] - newTrans[k]; - - tkk = t[k][k]; - } - - for (i = 0; i < 3; i++) { - if (i == k) { - continue - } - - q = t[i][k] / tkk; - t[i][k] = 0; - - for (j = k+1; j < 3; j++) { - t[i][j] -= t[k][j] * q; - } - for (j = 0; j < 3; j++) { - newTrans[i][j] -= newTrans[k][j] * q; - } - } - - for (j = k+1; j < 3; j++) { - t[k][j] /= tkk; - } - for (j = 0; j < 3; j++) { - newTrans[k][j] /= tkk; - } - - } - - return newTrans; - + affineTransformConcat: function (lhs, rhs) { + return new geometry.TransformMatrix( + lhs.a * rhs.a + lhs.b * rhs.c, + lhs.a * rhs.b + lhs.b * rhs.d, + lhs.c * rhs.a + lhs.d * rhs.c, + lhs.c * rhs.b + lhs.d * rhs.d, + lhs.tx * rhs.a + lhs.ty * rhs.c + rhs.tx, + lhs.tx * rhs.b + lhs.ty * rhs.d + rhs.ty + ); }, /** - * Multiply 2 transform (3x3) matrices together - * @returns {Float[]} New transform matrix + * @returns {Float} */ - affineTransformConcat: function(trans1, trans2) { - var newTrans = module.exports.affineTransformIdentity(); - - var x, y, i; - for (x = 0; x < 3; x++) { - for (y = 0; y < 3; y++) { - newTrans[y][x] = 0; - for (i = 0; i < 3; i++) { - newTrans[y][x] += trans1[y][i] * trans2[i][x]; - } - } - } - - return newTrans; + degreesToRadians: function (angle) { + return angle / 180.0 * Math.PI; }, /** * @returns {Float} */ - degressToRadians: function(angle) { - return angle / 180.0 * Math.PI; + radiansToDegrees: function (angle) { + return angle * (180.0 / Math.PI); }, /** - * @returns {Float[]} + * Translate (move) a transform matrix + * + * @param {geometry.TransformMatrix} trans TransformMatrix to translate + * @param {Float} tx Amount to translate along X axis + * @param {Float} ty Amount to translate along Y axis + * @returns {geometry.TransformMatrix} A new TransformMatrix */ - affineTransformTranslate: function(trans, x, y) { - // tx = 6, ty = 7 - + affineTransformTranslate: function (trans, tx, ty) { var newTrans = util.copy(trans); - newTrans[2][0] += x; - newTrans[2][1] += y; - + newTrans.tx = trans.tx + trans.a * tx + trans.c * ty; + newTrans.ty = trans.ty + trans.b * tx + trans.d * ty; return newTrans; }, - affineTransformRotate: function(trans, angle) { - // TODO - return trans; + /** + * Rotate a transform matrix + * + * @param {geometry.TransformMatrix} trans TransformMatrix to rotate + * @param {Float} angle Angle in radians + * @returns {geometry.TransformMatrix} A new TransformMatrix + */ + affineTransformRotate: function (trans, angle) { + var sin = Math.sin(angle), + cos = Math.cos(angle); + + return new geometry.TransformMatrix( + trans.a * cos + trans.c * sin, + trans.b * cos + trans.d * sin, + trans.c * cos - trans.a * sin, + trans.d * cos - trans.b * sin, + trans.tx, + trans.ty + ); }, - affineTransformScale: function(trans, scale) { - // TODO - return trans; + /** + * Scale a transform matrix + * + * @param {geometry.TransformMatrix} trans TransformMatrix to scale + * @param {Float} sx X scale factor + * @param {Float} [sy=sx] Y scale factor + * @returns {geometry.TransformMatrix} A new TransformMatrix + */ + affineTransformScale: function (trans, sx, sy) { + if (sy === undefined) { + sy = sx; + } + + return new geometry.TransformMatrix(trans.a * sx, trans.b * sx, trans.c * sy, trans.d * sy, trans.tx, trans.ty); }, /** - * @returns {Float[]} 3x3 identity matrix + * @returns {geometry.TransformMatrix} identity matrix */ - affineTransformIdentity: function() { - return [[1, 0, 0], - [0, 1, 0], - [0, 0, 1]]; + affineTransformIdentity: function () { + return new geometry.TransformMatrix(1, 0, 0, 1, 0, 0); } }; diff --git a/src/libs/gzip.js b/src/libs/gzip.js index 9a4887f..21a781d 100644 --- a/src/libs/gzip.js +++ b/src/libs/gzip.js @@ -39,7 +39,7 @@ var gzip = { * @returns {Integer[]} Unpacked byte array */ unzipBase64AsArray: function(input, bytes) { - var bytes = bytes || 1; + bytes = bytes || 1; var dec = this.unzipBase64(input), ar = [], i, j, len; @@ -60,7 +60,7 @@ var gzip = { * @returns {Integer[]} Unpacked byte array */ unzipAsArray: function (input, bytes) { - var bytes = bytes || 1; + bytes = bytes || 1; var dec = this.unzip(input), ar = [], i, j, len; diff --git a/src/libs/qunit.js b/src/libs/qunit.js new file mode 100644 index 0000000..30e0395 --- /dev/null +++ b/src/libs/qunit.js @@ -0,0 +1,1415 @@ +/* + * QUnit - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2011 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +(function(window) { + +var defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + try { + return !!sessionStorage.getItem; + } catch(e){ + return false; + } + })() +} + +var testId = 0; + +var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { + this.name = name; + this.testName = testName; + this.expected = expected; + this.testEnvironmentArg = testEnvironmentArg; + this.async = async; + this.callback = callback; + this.assertions = []; +}; +Test.prototype = { + init: function() { + var tests = id("qunit-tests"); + if (tests) { + var b = document.createElement("strong"); + b.innerHTML = "Running " + this.name; + var li = document.createElement("li"); + li.appendChild( b ); + li.id = this.id = "test-output" + testId++; + tests.appendChild( li ); + } + }, + setup: function() { + if (this.module != config.previousModule) { + if ( config.previousModule ) { + QUnit.moduleDone( { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + } ); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + QUnit.moduleStart( { + name: this.module + } ); + } + + config.current = this; + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment); + if (this.testEnvironmentArg) { + extend(this.testEnvironment, this.testEnvironmentArg); + } + + QUnit.testStart( { + name: this.testName + } ); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + try { + if ( !config.pollution ) { + saveGlobal(); + } + + this.testEnvironment.setup.call(this.testEnvironment); + } catch(e) { + QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); + } + }, + run: function() { + if ( this.async ) { + QUnit.stop(); + } + + if ( config.notrycatch ) { + this.callback.call(this.testEnvironment); + return; + } + try { + this.callback.call(this.testEnvironment); + } catch(e) { + fail("Test " + this.testName + " died, exception and test follows", e, this.callback); + QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + start(); + } + } + }, + teardown: function() { + try { + checkPollution(); + this.testEnvironment.teardown.call(this.testEnvironment); + } catch(e) { + QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); + } + }, + finish: function() { + if ( this.expected && this.expected != this.assertions.length ) { + QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); + } + + var good = 0, bad = 0, + tests = id("qunit-tests"); + + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + var ol = document.createElement("ol"); + + for ( var i = 0; i < this.assertions.length; i++ ) { + var assertion = this.assertions[i]; + + var li = document.createElement("li"); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad); + + if (bad == 0) { + ol.style.display = "none"; + } + + var b = document.createElement("strong"); + b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.nextSibling, display = next.style.display; + next.style.display = display === "none" ? "block" : "none"; + }); + + addEvent(b, "dblclick", function(e) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "")); + } + }); + + var li = id(this.id); + li.className = bad ? "fail" : "pass"; + li.style.display = resultDisplayStyle(!bad); + li.removeChild( li.firstChild ); + li.appendChild( b ); + li.appendChild( ol ); + + } else { + for ( var i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + try { + QUnit.reset(); + } catch(e) { + fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); + } + + QUnit.testDone( { + name: this.testName, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length + } ); + }, + + queue: function() { + var test = this; + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + // defer when previous test run passed, if storage is available + var bad = defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName); + if (bad) { + run(); + } else { + synchronize(run); + }; + } + +} + +var QUnit = { + + // call on start of module test to prepend name to all tests + module: function(name, testEnvironment) { + config.currentModule = name; + config.currentModuleTestEnviroment = testEnvironment; + }, + + asyncTest: function(testName, expected, callback) { + if ( arguments.length === 2 ) { + callback = expected; + expected = 0; + } + + QUnit.test(testName, expected, callback, true); + }, + + test: function(testName, expected, callback, async) { + var name = '' + testName + '', testEnvironmentArg; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + // is 2nd argument a testEnvironment? + if ( expected && typeof expected === 'object') { + testEnvironmentArg = expected; + expected = null; + } + + if ( config.currentModule ) { + name = '' + config.currentModule + ": " + name; + } + + if ( !validTest(config.currentModule + ": " + testName) ) { + return; + } + + var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); + test.module = config.currentModule; + test.moduleTestEnvironment = config.currentModuleTestEnviroment; + test.queue(); + }, + + /** + * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + */ + expect: function(asserts) { + config.current.expected = asserts; + }, + + /** + * Asserts true. + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function(a, msg) { + a = !!a; + var details = { + result: a, + message: msg + }; + msg = escapeHtml(msg); + QUnit.log(details); + config.current.assertions.push({ + result: a, + message: msg + }); + }, + + /** + * Checks that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * + * Prefered to ok( actual == expected, message ) + * + * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); + * + * @param Object actual + * @param Object expected + * @param String message (optional) + */ + equal: function(actual, expected, message) { + QUnit.push(expected == actual, actual, expected, message); + }, + + notEqual: function(actual, expected, message) { + QUnit.push(expected != actual, actual, expected, message); + }, + + deepEqual: function(actual, expected, message) { + QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); + }, + + notDeepEqual: function(actual, expected, message) { + QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); + }, + + strictEqual: function(actual, expected, message) { + QUnit.push(expected === actual, actual, expected, message); + }, + + notStrictEqual: function(actual, expected, message) { + QUnit.push(expected !== actual, actual, expected, message); + }, + + raises: function(block, expected, message) { + var actual, ok = false; + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + if (actual) { + // we don't want to validate thrown error + if (!expected) { + ok = true; + // expected is a regexp + } else if (QUnit.objectType(expected) === "regexp") { + ok = expected.test(actual); + // expected is a constructor + } else if (actual instanceof expected) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if (expected.call({}, actual) === true) { + ok = true; + } + } + + QUnit.ok(ok, message); + }, + + start: function() { + config.semaphore--; + if (config.semaphore > 0) { + // don't start until equal number of stop-calls + return; + } + if (config.semaphore < 0) { + // ignore if start is called more often then stop + config.semaphore = 0; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.timeout ) { + clearTimeout(config.timeout); + } + + config.blocking = false; + process(); + }, 13); + } else { + config.blocking = false; + process(); + } + }, + + stop: function(timeout) { + config.semaphore++; + config.blocking = true; + + if ( timeout && defined.setTimeout ) { + clearTimeout(config.timeout); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + QUnit.start(); + }, timeout); + } + } + +}; + +// Backwards compatibility, deprecated +QUnit.equals = QUnit.equal; +QUnit.same = QUnit.deepEqual; + +// Maintain internal state +var config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true +}; + +// Load paramaters +(function() { + var location = window.location || { search: "", protocol: "file:" }, + GETParams = location.search.slice(1).split('&'); + + for ( var i = 0; i < GETParams.length; i++ ) { + GETParams[i] = decodeURIComponent( GETParams[i] ); + if ( GETParams[i] === "noglobals" ) { + GETParams.splice( i, 1 ); + i--; + config.noglobals = true; + } else if ( GETParams[i] === "notrycatch" ) { + GETParams.splice( i, 1 ); + i--; + config.notrycatch = true; + } else if ( GETParams[i].search('=') > -1 ) { + GETParams.splice( i, 1 ); + i--; + } + } + + // restrict modules/tests by get parameters + config.filters = GETParams; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = !!(location.protocol === 'file:'); +})(); + +// Expose the API as global variables, unless an 'exports' +// object exists, in that case we assume we're in CommonJS +if ( typeof exports === "undefined" || typeof require === "undefined" ) { + extend(window, QUnit); + window.QUnit = QUnit; +} else { + extend(exports, QUnit); + exports.QUnit = QUnit; +} + +// define these after exposing globals to keep them in these QUnit namespace only +extend(QUnit, { + config: config, + + // Initialize the configuration options + init: function() { + extend(config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date, + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filters: [], + queue: [], + semaphore: 0 + }); + + var tests = id("qunit-tests"), + banner = id("qunit-banner"), + result = id("qunit-testresult"); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + }, + + /** + * Resets the test setup. Useful for tests that modify the DOM. + * + * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. + */ + reset: function() { + if ( window.jQuery ) { + jQuery( "#main, #qunit-fixture" ).html( config.fixture ); + } else { + var main = id( 'main' ) || id( 'qunit-fixture' ); + if ( main ) { + main.innerHTML = config.fixture; + } + } + }, + + /** + * Trigger an event on an element. + * + * @example triggerEvent( document.body, "click" ); + * + * @param DOMElement elem + * @param String type + */ + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent("MouseEvents"); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + elem.dispatchEvent( event ); + + } else if ( elem.fireEvent ) { + elem.fireEvent("on"+type); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) == type; + }, + + objectType: function( obj ) { + if (typeof obj === "undefined") { + return "undefined"; + + // consider: typeof null === object + } + if (obj === null) { + return "null"; + } + + var type = Object.prototype.toString.call( obj ) + .match(/^\[object\s(.*)\]$/)[1] || ''; + + switch (type) { + case 'Number': + if (isNaN(obj)) { + return "nan"; + } else { + return "number"; + } + case 'String': + case 'Boolean': + case 'Array': + case 'Date': + case 'RegExp': + case 'Function': + return type.toLowerCase(); + } + if (typeof obj === "object") { + return "object"; + } + return undefined; + }, + + push: function(result, actual, expected, message) { + var details = { + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeHtml(message) || (result ? "okay" : "failed"); + message = '' + message + ""; + expected = escapeHtml(QUnit.jsDump.parse(expected)); + actual = escapeHtml(QUnit.jsDump.parse(actual)); + var output = message + ''; + if (actual != expected) { + output += ''; + output += ''; + } + if (!result) { + var source = sourceFromStacktrace(); + if (source) { + details.source = source; + output += ''; + } + } + output += "
Expected:
' + expected + '
Result:
' + actual + '
Diff:
' + QUnit.diff(expected, actual) +'
Source:
' + source +'
"; + + QUnit.log(details); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: function() {}, + // done: { failed, passed, total, runtime } + done: function() {}, + // log: { result, actual, expected, message } + log: function() {}, + // testStart: { name } + testStart: function() {}, + // testDone: { name, failed, passed, total } + testDone: function() {}, + // moduleStart: { name } + moduleStart: function() {}, + // moduleDone: { name, failed, passed, total } + moduleDone: function() {} +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +addEvent(window, "load", function() { + QUnit.begin({}); + + // Initialize the config, saving the execution queue + var oldconfig = extend({}, config); + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + var userAgent = id("qunit-userAgent"); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + var banner = id("qunit-header"); + if ( banner ) { + var paramsIndex = location.href.lastIndexOf(location.search); + if ( paramsIndex > -1 ) { + var mainPageLocation = location.href.slice(0, paramsIndex); + if ( mainPageLocation == location.href ) { + banner.innerHTML = ' ' + banner.innerHTML + ' '; + } else { + var testName = decodeURIComponent(location.search.slice(1)); + banner.innerHTML = '' + banner.innerHTML + '' + testName + ''; + } + } + } + + var toolbar = id("qunit-testrunner-toolbar"); + if ( toolbar ) { + var filter = document.createElement("input"); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + addEvent( filter, "click", function() { + var li = document.getElementsByTagName("li"); + for ( var i = 0; i < li.length; i++ ) { + if ( li[i].className.indexOf("pass") > -1 ) { + li[i].style.display = filter.checked ? "none" : ""; + } + } + if ( defined.sessionStorage ) { + sessionStorage.setItem("qunit-filter-passed-tests", filter.checked ? "true" : ""); + } + }); + if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { + filter.checked = true; + } + toolbar.appendChild( filter ); + + var label = document.createElement("label"); + label.setAttribute("for", "qunit-filter-pass"); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + } + + var main = id('main') || id('qunit-fixture'); + if ( main ) { + config.fixture = main.innerHTML; + } + + if (config.autostart) { + QUnit.start(); + } +}); + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + QUnit.moduleDone( { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + } ); + } + + var banner = id("qunit-banner"), + tests = id("qunit-tests"), + runtime = +new Date - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + 'Tests completed in ', + runtime, + ' milliseconds.
', + '', + passed, + ' tests of ', + config.stats.all, + ' passed, ', + config.stats.bad, + ' failed.' + ].join(''); + + if ( banner ) { + banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); + } + + if ( tests ) { + var result = id("qunit-testresult"); + + if ( !result ) { + result = document.createElement("p"); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests.nextSibling ); + } + + result.innerHTML = html; + } + + QUnit.done( { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + } ); +} + +function validTest( name ) { + var i = config.filters.length, + run = false; + + if ( !i ) { + return true; + } + + while ( i-- ) { + var filter = config.filters[i], + not = filter.charAt(0) == '!'; + + if ( not ) { + filter = filter.slice(1); + } + + if ( name.indexOf(filter) !== -1 ) { + return !not; + } + + if ( not ) { + run = true; + } + } + + return run; +} + +// so far supports only Firefox, Chrome and Opera (buggy) +// could be extended in the future to use something like https://github.com/csnover/TraceKit +function sourceFromStacktrace() { + try { + throw new Error(); + } catch ( e ) { + if (e.stacktrace) { + // Opera + return e.stacktrace.split("\n")[6]; + } else if (e.stack) { + // Firefox, Chrome + return e.stack.split("\n")[4]; + } + } +} + +function resultDisplayStyle(passed) { + return passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked ? 'none' : ''; +} + +function escapeHtml(s) { + if (!s) { + return ""; + } + s = s + ""; + return s.replace(/[\&"<>\\]/g, function(s) { + switch(s) { + case "&": return "&"; + case "\\": return "\\\\"; + case '"': return '\"'; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); +} + +function synchronize( callback ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process(); + } +} + +function process() { + var start = (new Date()).getTime(); + + while ( config.queue.length && !config.blocking ) { + if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { + config.queue.shift()(); + } else { + window.setTimeout( process, 13 ); + break; + } + } + if (!config.blocking && !config.queue.length) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + config.pollution.push( key ); + } + } +} + +function checkPollution( name ) { + var old = config.pollution; + saveGlobal(); + + var newGlobals = diff( old, config.pollution ); + if ( newGlobals.length > 0 ) { + ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); + config.current.expected++; + } + + var deletedGlobals = diff( config.pollution, old ); + if ( deletedGlobals.length > 0 ) { + ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); + config.current.expected++; + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var result = a.slice(); + for ( var i = 0; i < result.length; i++ ) { + for ( var j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice(i, 1); + i--; + break; + } + } + } + return result; +} + +function fail(message, exception, callback) { + if ( typeof console !== "undefined" && console.error && console.warn ) { + console.error(message); + console.error(exception); + console.warn(callback.toString()); + + } else if ( window.opera && opera.postError ) { + opera.postError(message, exception, callback.toString); + } +} + +function extend(a, b) { + for ( var prop in b ) { + a[prop] = b[prop]; + } + + return a; +} + +function addEvent(elem, type, fn) { + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, fn ); + } else { + fn(); + } +} + +function id(name) { + return !!(typeof document !== "undefined" && document && document.getElementById) && + document.getElementById( name ); +} + +// Test for equality any JavaScript type. +// Discussions and reference: http://philrathe.com/articles/equiv +// Test suites: http://philrathe.com/tests/equiv +// Author: Philippe Rathé +QUnit.equiv = function () { + + var innerEquiv; // the real equiv function + var callers = []; // stack to decide between skip/abort functions + var parents = []; // stack to avoiding loops from circular referencing + + // Call the o related callback with the given arguments. + function bindCallbacks(o, callbacks, args) { + var prop = QUnit.objectType(o); + if (prop) { + if (QUnit.objectType(callbacks[prop]) === "function") { + return callbacks[prop].apply(callbacks, args); + } else { + return callbacks[prop]; // or undefined + } + } + } + + var callbacks = function () { + + // for string, boolean, number and null + function useStrictEquality(b, a) { + if (b instanceof a.constructor || a instanceof b.constructor) { + // to catch short annotaion VS 'new' annotation of a declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function (b) { + return isNaN(b); + }, + + "date": function (b, a) { + return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function (b, a) { + return QUnit.objectType(b) === "regexp" && + a.source === b.source && // the regex itself + a.global === b.global && // and its modifers (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function () { + var caller = callers[callers.length - 1]; + return caller !== Object && + typeof caller !== "undefined"; + }, + + "array": function (b, a) { + var i, j, loop; + var len; + + // b could be an object literal here + if ( ! (QUnit.objectType(b) === "array")) { + return false; + } + + len = a.length; + if (len !== b.length) { // safe and faster + return false; + } + + //track reference to avoid circular references + parents.push(a); + for (i = 0; i < len; i++) { + loop = false; + for(j=0;j= 0) { + type = "array"; + } else { + type = typeof obj; + } + return type; + }, + separator:function() { + return this.multiline ? this.HTML ? '
' : '\n' : this.HTML ? ' ' : ' '; + }, + indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing + if ( !this.multiline ) + return ''; + var chr = this.indentChar; + if ( this.HTML ) + chr = chr.replace(/\t/g,' ').replace(/ /g,' '); + return Array( this._depth_ + (extra||0) ).join(chr); + }, + up:function( a ) { + this._depth_ += a || 1; + }, + down:function( a ) { + this._depth_ -= a || 1; + }, + setParser:function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote:quote, + literal:literal, + join:join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers:{ + window: '[Window]', + document: '[Document]', + error:'[ERROR]', //when no parser is found, shouldn't happen + unknown: '[Unknown]', + 'null':'null', + undefined:'undefined', + 'function':function( fn ) { + var ret = 'function', + name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE + if ( name ) + ret += ' ' + name; + ret += '('; + + ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); + return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); + }, + array: array, + nodelist: array, + arguments: array, + object:function( map ) { + var ret = [ ]; + QUnit.jsDump.up(); + for ( var key in map ) + ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); + QUnit.jsDump.down(); + return join( '{', ret, '}' ); + }, + node:function( node ) { + var open = QUnit.jsDump.HTML ? '<' : '<', + close = QUnit.jsDump.HTML ? '>' : '>'; + + var tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for ( var a in QUnit.jsDump.DOMAttrs ) { + var val = node[QUnit.jsDump.DOMAttrs[a]]; + if ( val ) + ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); + } + return ret + close + open + '/' + tag + close; + }, + functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function + var l = fn.length; + if ( !l ) return ''; + + var args = Array(l); + while ( l-- ) + args[l] = String.fromCharCode(97+l);//97 is 'a' + return ' ' + args.join(', ') + ' '; + }, + key:quote, //object calls it internally, the key part of an item in a map + functionCode:'[code]', //function calls it internally, it's the content of the function + attribute:quote, //node calls it internally, it's an html attribute value + string:quote, + date:quote, + regexp:literal, //regex + number:literal, + 'boolean':literal + }, + DOMAttrs:{//attributes to dump from nodes, name=>realName + id:'id', + name:'name', + 'class':'className' + }, + HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) + indentChar:' ',//indentation unit + multiline:true //if true, items in a collection, are separated by a \n, else just a space. + }; + + return jsDump; +})(); + +// from Sizzle.js +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +}; + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + function diff(o, n){ + var ns = new Object(); + var os = new Object(); + + for (var i = 0; i < n.length; i++) { + if (ns[n[i]] == null) + ns[n[i]] = { + rows: new Array(), + o: null + }; + ns[n[i]].rows.push(i); + } + + for (var i = 0; i < o.length; i++) { + if (os[o[i]] == null) + os[o[i]] = { + rows: new Array(), + n: null + }; + os[o[i]].rows.push(i); + } + + for (var i in ns) { + if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { + n[ns[i].rows[0]] = { + text: n[ns[i].rows[0]], + row: os[i].rows[0] + }; + o[os[i].rows[0]] = { + text: o[os[i].rows[0]], + row: ns[i].rows[0] + }; + } + } + + for (var i = 0; i < n.length - 1; i++) { + if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && + n[i + 1] == o[n[i].row + 1]) { + n[i + 1] = { + text: n[i + 1], + row: n[i].row + 1 + }; + o[n[i].row + 1] = { + text: o[n[i].row + 1], + row: i + 1 + }; + } + } + + for (var i = n.length - 1; i > 0; i--) { + if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && + n[i - 1] == o[n[i].row - 1]) { + n[i - 1] = { + text: n[i - 1], + row: n[i].row - 1 + }; + o[n[i].row - 1] = { + text: o[n[i].row - 1], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function(o, n){ + o = o.replace(/\s+$/, ''); + n = n.replace(/\s+$/, ''); + var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); + + var str = ""; + + var oSpace = o.match(/\s+/g); + if (oSpace == null) { + oSpace = [" "]; + } + else { + oSpace.push(" "); + } + var nSpace = n.match(/\s+/g); + if (nSpace == null) { + nSpace = [" "]; + } + else { + nSpace.push(" "); + } + + if (out.n.length == 0) { + for (var i = 0; i < out.o.length; i++) { + str += '' + out.o[i] + oSpace[i] + ""; + } + } + else { + if (out.n[0].text == null) { + for (n = 0; n < out.o.length && out.o[n].text == null; n++) { + str += '' + out.o[n] + oSpace[n] + ""; + } + } + + for (var i = 0; i < out.n.length; i++) { + if (out.n[i].text == null) { + str += '' + out.n[i] + nSpace[i] + ""; + } + else { + var pre = ""; + + for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { + pre += '' + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +})(); + +})(this); diff --git a/src/libs/util.js b/src/libs/util.js index dfc58c9..85e68c1 100644 --- a/src/libs/util.js +++ b/src/libs/util.js @@ -109,7 +109,7 @@ var util = { throw "You must provide at least a target and 1 object to extend from" } - var i, obj, key, val; + var i, j, obj, key, val; for (i = 1; i < arguments.length; i++) { obj = arguments[i]; @@ -145,9 +145,8 @@ var util = { } - var i; - for (i = 0; i

+ /// The main entry point for the application. + /// + [STAThread] + static void Main(String[] args) + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + FolderBrowserDialog dialog = new FolderBrowserDialog(); + dialog.Description = "Create and select the folder for the new Cocos2D JavaScript project you want to create."; + String filename; + + if (args.Length > 0) + { + filename = args[0]; + } + else + { + filename = (dialog.ShowDialog() == DialogResult.OK) ? dialog.SelectedPath : null; + } + + if (filename != null) + { + String exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + String oldDir = System.IO.Directory.GetCurrentDirectory(); + System.IO.Directory.SetCurrentDirectory(filename); + Cocos.Command("new", ".", true); + + // Create shortcuts + Create.Shortcut(exeDir + @"\Serve project.exe", filename + @"\Serve project.lnk"); + Create.Shortcut(exeDir + @"\Compile project.exe", filename + @"\Compile project.lnk"); + + Process.Start(new ProcessStartInfo("explorer.exe", filename)); + } + } + + static void Shortcut(String source, String dest, String description="") + { + WshShell wsh = new WshShellClass(); + + IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)wsh.CreateShortcut(dest); + shortcut.Arguments = "."; + shortcut.TargetPath = source; + + shortcut.Save(); + } + + } +} diff --git a/support/win32/utils/Cocos2D JavaScript/Make.cs b/support/win32/utils/Cocos2D JavaScript/Make.cs new file mode 100644 index 0000000..de7f6a0 --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Make.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using System.Diagnostics; +using System.IO; +using System.Reflection; + +namespace Cocos2D_JavaScript +{ + static class Make + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(String[] args) + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + FolderBrowserDialog dialog = new FolderBrowserDialog(); + dialog.Description = "Select the folder of the Cocos2D JavaScript project you want to compile."; + + String filename; + if (args.Length > 0) + { + filename = args[0]; + } + else + { + filename = (dialog.ShowDialog() == DialogResult.OK) ? dialog.SelectedPath : null; + } + + if (filename != null) + { + System.IO.Directory.SetCurrentDirectory(filename); + Cocos.Command("make", "", true); + Process.Start(new ProcessStartInfo("explorer.exe ", filename + "\\build\\")); + } + + + } + } +} diff --git a/support/win32/utils/Cocos2D JavaScript/Properties/AssemblyInfo.cs b/support/win32/utils/Cocos2D JavaScript/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8df484f --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Cocos2D JavaScript")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Ryan Williams")] +[assembly: AssemblyProduct("Cocos2D JavaScript")] +[assembly: AssemblyCopyright("Copyright 2011 Ryan Williams")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7019d3e5-78dc-4854-9bab-b8b4e51403f5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.0.1.0")] +[assembly: AssemblyFileVersion("0.0.1.0")] diff --git a/support/win32/utils/Cocos2D JavaScript/Properties/Resources.Designer.cs b/support/win32/utils/Cocos2D JavaScript/Properties/Resources.Designer.cs new file mode 100644 index 0000000..08ab5a8 --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Cocos2D_JavaScript.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Cocos2D_JavaScript.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/support/win32/utils/Cocos2D JavaScript/Properties/Resources.resx b/support/win32/utils/Cocos2D JavaScript/Properties/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/support/win32/utils/Cocos2D JavaScript/Properties/Settings.Designer.cs b/support/win32/utils/Cocos2D JavaScript/Properties/Settings.Designer.cs new file mode 100644 index 0000000..9aff387 --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Cocos2D_JavaScript.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/support/win32/utils/Cocos2D JavaScript/Properties/Settings.settings b/support/win32/utils/Cocos2D JavaScript/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/support/win32/utils/Cocos2D JavaScript/Server.cs b/support/win32/utils/Cocos2D JavaScript/Server.cs new file mode 100644 index 0000000..0d26a9f --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/Server.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using System.Diagnostics; +using System.IO; +using System.Reflection; + +namespace Cocos2D_JavaScript +{ + static class Server + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(String[] args) + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + FolderBrowserDialog dialog = new FolderBrowserDialog(); + dialog.Description = "Select the folder of the Cocos2D JavaScript project you want to run a development Web server for."; + + String filename; + if (args.Length > 0) + { + filename = args[0]; + } + else + { + filename = (dialog.ShowDialog() == DialogResult.OK) ? dialog.SelectedPath : null; + } + + if (filename != null) + { + System.IO.Directory.SetCurrentDirectory(filename); + Cocos.Command("server"); + } + } + } +} diff --git a/support/win32/utils/Cocos2D JavaScript/app.config b/support/win32/utils/Cocos2D JavaScript/app.config new file mode 100644 index 0000000..8494f72 --- /dev/null +++ b/support/win32/utils/Cocos2D JavaScript/app.config @@ -0,0 +1,3 @@ + + + diff --git a/support/win32/utils/Cocos2D JavaScript/cocos2d - Happy.ico b/support/win32/utils/Cocos2D JavaScript/cocos2d - Happy.ico new file mode 100644 index 0000000..c1a268c Binary files /dev/null and b/support/win32/utils/Cocos2D JavaScript/cocos2d - Happy.ico differ diff --git a/tests/cocos2d/SpriteTest.js b/tests/cocos2d/SpriteTest.js deleted file mode 100644 index 22788c0..0000000 --- a/tests/cocos2d/SpriteTest.js +++ /dev/null @@ -1,487 +0,0 @@ -var util = require('util'), - Texture2D = require('cocos2d/Texture2D').Texture2D, - cocos = require('cocos2d'), - nodes = cocos.nodes, - actions = cocos.actions, - geo = require('geometry'), - ccp = geo.ccp; - -var sceneIdx = -1; -var transitions = [ - "Sprite1", - "SpriteBatchNode1", - "SpriteAnchorPoint", - "SpriteAnimationFlip", - "SpriteZOrder", - "AnimationCache" -]; - -var kTagTileMap = 1, - kTagSpriteBatchNode = 1, - kTagNode = 2, - kTagAnimation1 = 1, - kTagSpriteLeft = 2, - kTagSpriteRight = 3; - -var kTagSprite1 = 1, - kTagSprite2 = 2, - kTagSprite3 = 3, - kTagSprite4 = 4, - kTagSprite5 = 5, - kTagSprite6 = 6, - kTagSprite7 = 7, - kTagSprite8 = 8; - -function nextAction() { - sceneIdx++; - sceneIdx = sceneIdx % transitions.length; - - var r = transitions[sceneIdx]; - var c = eval('(' + r + ')'); - return c; -} -function backAction() { - sceneIdx--; - if (sceneIdx < 0) { - sceneIdx += transitions.length; - } - - var r = transitions[sceneIdx]; - var c = eval('(' + r + ')'); - return c; -} -function restartAction() { - var r = transitions[sceneIdx]; - var c = eval('(' + r + ')'); - return c; -} - -var SpriteDemo = nodes.Layer.extend({ - title: 'No title', - subtitle: null, - - init: function() { - @super; - - var s = cocos.Director.get('sharedDirector').get('winSize'); - - var label = nodes.Label.create({string: this.get('title'), fontName: 'Arial', fontSize: 26}); - this.addChild({child: label, z:1}); - label.set('position', ccp(s.width / 2, 50)); - - - var subtitle = this.get('subtitle'); - if (subtitle) { - var l = nodes.Label.create({string:subtitle, fontName: "Thonburi", fontSize: 16}); - this.addChild({child: l, z:1}); - l.set('position', ccp(s.width/2, 80)); - } - - - var item1 = nodes.MenuItemImage.create({normalImage:__dirname + "/resources/b1.png", selectedImage:__dirname + "/resources/b2.png", callback:util.callback(this, 'backCallback')}); - var item2 = nodes.MenuItemImage.create({normalImage:__dirname + "/resources/r1.png", selectedImage:__dirname + "/resources/r2.png", callback:util.callback(this, 'restartCallback')}); - var item3 = nodes.MenuItemImage.create({normalImage:__dirname + "/resources/f1.png", selectedImage:__dirname + "/resources/f2.png", callback:util.callback(this, 'nextCallback')}); - - var menu = nodes.Menu.create({items: [item1, item2, item3]}); - - menu.set('position', ccp(0,0)); - item1.set('position', ccp(s.width /2 -100, s.height -30)); - item2.set('position', ccp(s.width /2, s.height -30)); - item3.set('position', ccp(s.width /2 +100, s.height -30)); - this.addChild({child: menu, z:1}); - }, - - restartCallback: function() { - var director = cocos.Director.get('sharedDirector'); - - var scene = nodes.Scene.create(); - scene.addChild({child: restartAction().create()}); - - director.replaceScene(scene); - }, - - backCallback: function() { - var director = cocos.Director.get('sharedDirector'); - - var scene = nodes.Scene.create(); - scene.addChild({child: backAction().create()}); - - director.replaceScene(scene); - }, - - nextCallback: function() { - var director = cocos.Director.get('sharedDirector'); - - var scene = nodes.Scene.create(); - scene.addChild({child: nextAction().create()}); - - director.replaceScene(scene); - } -}); - -/** - * @class - * - * Example Sprite 1 - */ -var Sprite1 = SpriteDemo.extend(/** @lends Sprite1.prototype# */{ - title: 'Sprite', - subtitle: 'Click screen', - - init: function() { - @super; - this.set('isMouseEnabled', true); - - var s = cocos.Director.get('sharedDirector').get('winSize'); - this.addNewSprite(ccp(s.width /2, s.height /2)); - }, - - addNewSprite: function(point) { - var idx = Math.floor(Math.random() * 1400 / 100), - x = (idx%5) * 85, - y = (idx%3) * 121; - - var sprite = nodes.Sprite.create({file: __dirname + "/resources/grossini_dance_atlas.png", rect:{origin:ccp(x, y), size:{width: 85, height: 121}}}) - this.addChild({child:sprite, z:0}); - sprite.set('position', ccp(point.x, point.y)); - - var action, actionBack, seq; - var rand = Math.random(); - - if (rand < 0.2) { - action = actions.ScaleBy.create({duration:3, scale:2}); - } else if (rand < 0.4) { - action = actions.RotateBy.create({duration:3, angle:360}); - } else if (rand < 0.6) { - action = actions.ScaleBy.create({duration:3, scale:2}); - //action = cocos.Blink.create({duration:3, scale:2}); - } else if (rand < 0.8) { - action = actions.RotateBy.create({duration:3, angle:360}); - //action = cocos.TintBy.create({duration:3, scale:2}); - } else { - action = actions.ScaleBy.create({duration:3, scale:2}); - //action = cocos.FadeOut.create({duration:3, scale:2}); - } - - - - - actionBack = action.reverse(); - seq = actions.Sequence.create({actions:[action, actionBack]}); - sprite.runAction(actions.RepeatForever.create(seq)); - - }, - mouseUp: function(event) { - var location = cocos.Director.get('sharedDirector').convertEventToCanvas(event); - this.addNewSprite(location); - - return true; - } -}); - - -/** - * @class - * - * Example SpriteBatchNode 1 - */ -var SpriteBatchNode1 = SpriteDemo.extend(/** @lends SpriteBatchNode1.prototype# */{ - title: 'SpriteBatchNode', - subtitle: 'Click screen', - - init: function() { - @super; - this.set('isMouseEnabled', true); - - var batch = nodes.SpriteBatchNode.create({file: __dirname + "/resources/grossini_dance_atlas.png", size: geo.sizeMake(480, 320)}); - this.addChild({child: batch, z: 0, tag: kTagSpriteBatchNode}); - - var s = cocos.Director.get('sharedDirector').get('winSize'); - this.addNewSprite(ccp(s.width /2, s.height /2)); - }, - - addNewSprite: function(point) { - var batch = this.getChild({tag: kTagSpriteBatchNode}); - - var idx = Math.floor(Math.random() * 1400 / 100), - x = (idx%5) * 85, - y = (idx%3) * 121; - - var sprite = nodes.Sprite.create({textureAtlas: batch.get('textureAtlas'), rect:geo.rectMake(x, y, 85, 121)}) - batch.addChild({child:sprite}); - - sprite.set('position', ccp(point.x, point.y)); - - var action, actionBack, seq; - var rand = Math.random(); - - if (rand < 0.2) { - action = actions.ScaleBy.create({duration:3, scale:2}); - } else if (rand < 0.4) { - action = actions.RotateBy.create({duration:3, angle:360}); - } else if (rand < 0.6) { - action = actions.ScaleBy.create({duration:3, scale:2}); - //action = cocos.Blink.create({duration:3, scale:2}); - } else if (rand < 0.8) { - action = actions.RotateBy.create({duration:3, angle:360}); - //action = cocos.TintBy.create({duration:3, scale:2}); - } else { - action = actions.ScaleBy.create({duration:3, scale:2}); - //action = cocos.FadeOut.create({duration:3, scale:2}); - } - - actionBack = action.reverse(); - seq = actions.Sequence.create({actions:[action, actionBack]}); - sprite.runAction(actions.RepeatForever.create(seq)); - }, - mouseUp: function(event) { - - var location = cocos.Director.get('sharedDirector').convertEventToCanvas(event); - this.addNewSprite(location); - - return true; - } -}); - - -/** - * @class - * - * Example Sprite Animation and flip - */ -var SpriteAnimationFlip = SpriteDemo.extend(/** @lends SpriteAnimationFlip.prototype# */{ - title: 'Sprite Animation + Flip', - - init: function() { - @super; - - var s = cocos.Director.get('sharedDirector').get('winSize'); - - var texture = Texture2D.create({file: __dirname + "/resources/animations/dragon_animation.png"}); - - var frame0 = cocos.SpriteFrame.create({texture: texture, rect: geo.rectMake(132*0, 132*0, 132, 132)}), - frame1 = cocos.SpriteFrame.create({texture: texture, rect: geo.rectMake(132*1, 132*0, 132, 132)}), - frame2 = cocos.SpriteFrame.create({texture: texture, rect: geo.rectMake(132*2, 132*0, 132, 132)}), - frame3 = cocos.SpriteFrame.create({texture: texture, rect: geo.rectMake(132*3, 132*0, 132, 132)}), - frame4 = cocos.SpriteFrame.create({texture: texture, rect: geo.rectMake(132*0, 132*1, 132, 132)}), - frame5 = cocos.SpriteFrame.create({texture: texture, rect: geo.rectMake(132*1, 132*1, 132, 132)}); - - - var sprite = nodes.Sprite.create({frame: frame0}); - sprite.set('position', ccp(s.width/2 - 80, s.height/2)); - this.addChild(sprite); - - var animFrames = [ - frame0, - frame1, - frame2, - frame3, - frame4, - frame5 - ]; - - - var animation = cocos.Animation.create({frames: animFrames, delay:0.2}), - animate = actions.Animate.create({animation: animation, restoreOriginalFrame: false}), - seq = actions.Sequence.create({actions: [animate, - actions.FlipX.create({flipX: true}), - animate.copy(), - actions.FlipX.create({flipX: false})]}); - - sprite.runAction(actions.RepeatForever.create(seq)); - } -}); - -/** - * @class - * - * Example Sprite Anchor Point - */ -var SpriteAnchorPoint = SpriteDemo.extend(/** @lends SpriteAnchorPoint.prototype# */{ - title: 'Sprite Anchor Point', - - init: function() { - @super; - - var s = cocos.Director.get('sharedDirector').get('winSize'); - - var rotate = actions.RotateBy.create({duration: 10, angle: 360}); - var action = actions.RepeatForever.create(rotate); - for (var i=0; i<3; i++) { - var sprite = nodes.Sprite.create({file: __dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85*i, 121*1, 85, 121)}); - sprite.position = ccp(s.width/4*(i+1), s.height/2); - - var point = nodes.Sprite.create({file: __dirname + "/resources/r1.png"}); - point.set('scale', 0.25); - point.set('position', sprite.get('position')); - this.addChild({child: point, z: 10}); - - switch(i) { - case 0: - sprite.set('anchorPoint', ccp(0, 0)); - break; - case 1: - sprite.set('anchorPoint', ccp(0.5, 0.5)); - break; - case 2: - sprite.set('anchorPoint', ccp(1, 1)); - break; - } - - point.set('position', sprite.get('position')); - - var copy = action.copy(); - sprite.runAction(copy); - this.addChild({child: sprite, z: 1}); - } - } -}); - - -/** - * @class - * - * Example Sprite Z ORder - */ -var SpriteZOrder = SpriteDemo.extend(/** @lends SpriteZOrder.prototype# */{ - title: 'Sprite Z Order', - dir: 1, - - init: function() { - @super; - - var s = cocos.Director.get('sharedDirector').get('winSize'); - - var step = s.width / 11; - for (var i=0; i<5; i++) { - var sprite = nodes.Sprite.create({file: __dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85*0, 121*1, 85, 121)}); - sprite.set('position', ccp((i+1)*step, s.height/2)); - this.addChild({child: sprite, z: i}); - } - - for (var i=5; i<10; i++) { - var sprite = nodes.Sprite.create({file: __dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85*1, 121*0, 85, 121)}); - sprite.set('position', ccp((i+1)*step, s.height/2)); - this.addChild({child: sprite, z: 14-i}); - } - - var sprite = nodes.Sprite.create({file: __dirname + "/resources/grossini_dance_atlas-red.png", rect: geo.rectMake(85*3, 121*0, 85, 121)}); - this.addChild({child: sprite, z: -1, tag: kTagSprite1}); - - sprite.set('position', ccp(s.width/2, s.height/2 + 20)); - sprite.set('scaleX', 6); - - cocos.Scheduler.get('sharedScheduler').schedule({target: this, method: this.reorderSprite, interval: 1}); - }, - reorderSprite: function(dt) { - var sprite = this.getChild({tag: kTagSprite1}); - var z = sprite.get('zOrder'); - - if (z < -1) - this.dir = 1; - if (z > 10) - this.dir = -1; - - z += this.dir * 3; - - this.reorderChild({child: sprite, z: z}); - } -}); - -/** - * @class - * - * Example using AnimationCache and loading from a Zwoptex .plist file - */ -var AnimationCache = SpriteDemo.extend(/** @lends AnimationCache.prototype# */{ - title: 'AnimationCache', - subtitle: 'Sprite should be animated', - - init: function() { - @super; - - var frameCache = cocos.SpriteFrameCache.get('sharedSpriteFrameCache'), - animCache = cocos.AnimationCache.get('sharedAnimationCache'); - - frameCache.addSpriteFrames({file: __dirname + '/resources/animations/grossini.plist'}); - frameCache.addSpriteFrames({file: __dirname + '/resources/animations/grossini_gray.plist'}); - frameCache.addSpriteFrames({file: __dirname + '/resources/animations/grossini_blue.plist'}); - - - // create "dance" animation - var animFrames = [], - frame; - for (var i = 1; i < 15; i++) { - frame = frameCache.getSpriteFrame({name: 'grossini_dance_' + (i >= 10 ? i : '0' + i) + '.png'}); - animFrames.push(frame); - } - - var animation = cocos.Animation.create({frames: animFrames, delay:0.2}); - - // Add an animation to the Cache - animCache.addAnimation({animation: animation, name: 'dance'}); - - - // create animation "dance gray" - animFrames = []; - for (var i = 1; i < 15; i++) { - frame = frameCache.getSpriteFrame({name: 'grossini_dance_gray_' + (i >= 10 ? i : '0' + i) + '.png'}); - animFrames.push(frame); - } - - animation = cocos.Animation.create({frames: animFrames, delay:0.2}); - - // Add an animation to the Cache - animCache.addAnimation({animation: animation, name: 'dance_gray'}); - - - // create animation "dance blue" - animFrames = []; - for (var i = 1; i < 4; i++) { - frame = frameCache.getSpriteFrame({name: 'grossini_blue_0' + i + '.png'}); - animFrames.push(frame); - } - - animation = cocos.Animation.create({frames: animFrames, delay:0.2}); - - // Add an animation to the Cache - animCache.addAnimation({animation: animation, name: 'dance_blue'}); - - - var normal = animCache.getAnimation({name: 'dance'}), - dance_gray = animCache.getAnimation({name: 'dance_gray'}), - dance_blue = animCache.getAnimation({name: 'dance_blue'}); - - var animN = actions.Animate.create({animation: normal}), - animG = actions.Animate.create({animation: dance_gray}), - animB = actions.Animate.create({animation: dance_blue}); - - var seq = actions.Sequence.create({actions: [animN, animG, animB]}); - - // create an sprite without texture - var grossini = nodes.Sprite.create(); - - var winSize = cocos.Director.get('sharedDirector').get('winSize'); - - grossini.set('position', ccp(winSize.width/2, winSize.height/2)); - - this.addChild({child: grossini}); - - - // run the animation - grossini.runAction(seq); - } -}); - - - -// Initialise test -var director = cocos.Director.get('sharedDirector'); - -director.attachInView(document.getElementById('cocos2d-tests')); -director.set('displayFPS', true); - -var scene = nodes.Scene.create(); -scene.addChild({child: nextAction().create()}); - -director.runWithScene(scene); diff --git a/tests/cocos2d/TileMapTest.js b/tests/cocos2d/TileMapTest.js deleted file mode 100644 index 00a5ca9..0000000 --- a/tests/cocos2d/TileMapTest.js +++ /dev/null @@ -1,144 +0,0 @@ -var util = require('util'), - Texture2D = require('cocos2d/Texture2D').Texture2D, - cocos = require('cocos2d'), - nodes = cocos.nodes, - actions = cocos.actions, - geo = require('geometry'), - ccp = geo.ccp; - -var sceneIdx = -1; -var transitions = [ - "TMXOrthoTest2" -]; - - -var kTagTileMap = 1; - -function nextAction() { - sceneIdx++; - sceneIdx = sceneIdx % transitions.length; - - var r = transitions[sceneIdx]; - var c = eval('(' + r + ')'); - return c; -} -function backAction() { - sceneIdx--; - if (sceneIdx < 0) { - sceneIdx += transitions.length; - } - - var r = transitions[sceneIdx]; - var c = eval('(' + r + ')'); - return c; -} -function restartAction() { - var r = transitions[sceneIdx]; - var c = eval('(' + r + ')'); - return c; -} - -var TileDemo = nodes.Layer.extend({ - title: 'No title', - subtitle: null, - - init: function() { - @super; - - this.set('isMouseEnabled', true); - - var s = cocos.Director.get('sharedDirector').get('winSize'); - - var label = nodes.Label.create({string: this.get('title'), fontName: 'Arial', fontSize: 26}); - this.addChild({child: label, z:1}); - label.set('position', ccp(s.width / 2, 50)); - - - var subtitle = this.get('subtitle'); - if (subtitle) { - var l = nodes.Label.create({string:subtitle, fontName: "Thonburi", fontSize: 16}); - this.addChild({child: l, z:1}); - l.set('position', ccp(s.width/2, 80)); - } - - - var item1 = nodes.MenuItemImage.create({normalImage:__dirname + "/resources/b1.png", selectedImage:__dirname + "/resources/b2.png", callback:util.callback(this, 'backCallback')}); - var item2 = nodes.MenuItemImage.create({normalImage:__dirname + "/resources/r1.png", selectedImage:__dirname + "/resources/r2.png", callback:util.callback(this, 'restartCallback')}); - var item3 = nodes.MenuItemImage.create({normalImage:__dirname + "/resources/f1.png", selectedImage:__dirname + "/resources/f2.png", callback:util.callback(this, 'nextCallback')}); - - var menu = nodes.Menu.create({items: [item1, item2, item3]}); - - menu.set('position', ccp(0,0)); - item1.set('position', ccp(s.width /2 -100, s.height -30)); - item2.set('position', ccp(s.width /2, s.height -30)); - item3.set('position', ccp(s.width /2 +100, s.height -30)); - this.addChild({child: menu, z:1}); - }, - - mouseDragged: function(event) { - var node = this.getChild({tag: kTagTileMap}); - var currentPos = node.get('position'); - node.set('position', geo.ccpAdd(currentPos, ccp(event.deltaX, event.deltaY))); - return true; - }, - - restartCallback: function() { - var director = cocos.Director.get('sharedDirector'); - - var scene = nodes.Scene.create(); - scene.addChild({child: restartAction().create()}); - - director.replaceScene(scene); - }, - - backCallback: function() { - var director = cocos.Director.get('sharedDirector'); - - var scene = nodes.Scene.create(); - scene.addChild({child: backAction().create()}); - - director.replaceScene(scene); - }, - - nextCallback: function() { - var director = cocos.Director.get('sharedDirector'); - - var scene = nodes.Scene.create(); - scene.addChild({child: nextAction().create()}); - - director.replaceScene(scene); - } -}); - - -var TMXOrthoTest2 = TileDemo.extend({ - title: 'Tile Map Test', - subtitle: 'drag screen', - - init: function() { - @super; - - var map = nodes.TMXTiledMap.create({file: __dirname + "/resources/TileMaps/orthogonal-test1.tmx"}); - this.addChild({child: map, z: 0, tag: kTagTileMap}); - - var s = cocos.Director.get('sharedDirector').get('winSize'); - - // Adjust anchor and position to bottom left so it renders like cocos2d-iphone - map.set('anchorPoint', ccp(0, 1)); - - map.set('position', ccp(0, s.height)); - - map.runAction(actions.ScaleBy.create({duration: 2, scale: 0.5})); - } -}); - -// Initialise test -var director = cocos.Director.get('sharedDirector'); - -director.attachInView(document.getElementById('cocos2d-tests')); -director.set('displayFPS', true); - -var scene = nodes.Scene.create(); -scene.addChild({child: nextAction().create()}); - -director.runWithScene(scene); diff --git a/tests/cocos2d/resources/TileMaps/orthogonal-test1.tmx b/tests/cocos2d/resources/TileMaps/orthogonal-test1.tmx deleted file mode 100644 index db2e170..0000000 --- a/tests/cocos2d/resources/TileMaps/orthogonal-test1.tmx +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - H4sIAAAAAAAAA9XMzQpAQBhG4cnfwsK/sJVBuf/7c9Sn3o0aWXnrSTNz4ty/N4iQTSJkBUpUdp4futa+m4gRIUGKTNq7X7Fbr2usud48Frv3osaBER166/OX/Zf/n+tha6FAAgAA - - - diff --git a/tests/main.js b/tests/main.js deleted file mode 100644 index 66bc35e..0000000 --- a/tests/main.js +++ /dev/null @@ -1,13 +0,0 @@ -var params = window.location.search; -if (params) { - var name = params.split('=')[1]; - require(name); -} else { - var c = document.getElementById('cocos2d-tests'); - with (c.style) { - textAlign = 'center'; - fontSize = '20pt'; - lineHeight = c.clientHeight + 'px'; - } - c.appendChild(document.createTextNode('Select a test to run')); -} diff --git a/tests/make.json b/tests/make.json new file mode 100644 index 0000000..d93f734 --- /dev/null +++ b/tests/make.json @@ -0,0 +1,15 @@ +{ + // Where to write the files to + "output": { + "script": "tests.js", + "resources": "resources/" + }, + + "pack_resources": false, + + // Paths to the code that should be included in the application + "paths": { + "src/commonjs/tests/" : "/commonjs/", + "src/" : "/" + } +} diff --git a/tests/public/index.html b/tests/public/index.html new file mode 100644 index 0000000..5811122 --- /dev/null +++ b/tests/public/index.html @@ -0,0 +1,257 @@ + + + + + + Cocos2D -- Tests + + + +

Tests

+

Select a test suite to run:

+ +
+

+
+

+
    +
    test markup, will be hidden
    +
    + + diff --git a/tests/src/cocos2d/ActionTest.js b/tests/src/cocos2d/ActionTest.js new file mode 100644 index 0000000..20f05e3 --- /dev/null +++ b/tests/src/cocos2d/ActionTest.js @@ -0,0 +1,736 @@ +/* module exports resource require*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + Texture2D = require('cocos2d/Texture2D').Texture2D, + Scheduler = require('cocos2d/Scheduler').Scheduler, + cocos = require('cocos2d'), + events = require('events'), + nodes = cocos.nodes, + actions = cocos.actions, + geo = require('geometry'), + ccp = geo.ccp; + +var sceneIdx = -1; +var transitions = [ + "Manual", + "Move", + "Jump", + "Bezier", + "Blink", + "Sequence", + "Sequence2", + "Spawn", + "Reverse", + "Delay", + "Repeat", + "RepeatForever", + "RotateToRepeat", + "RotateJerk", + "ReverseSequence", + "ReverseSequence2", + "Speed", + "Follow" +]; + +var tests = {}; + +var kTagSprite1 = 1, + kTagSprite2 = 2, + kTagSprite3 = 3; + +var kTagAction1 = 1, + kTagAction2 = 2, + kTagSlider = 1; + +function nextAction() { + sceneIdx++; + sceneIdx = sceneIdx % transitions.length; + + var r = transitions[sceneIdx]; + return tests[r]; +} +function backAction() { + sceneIdx--; + if (sceneIdx < 0) { + sceneIdx += transitions.length; + } + + var r = transitions[sceneIdx]; + return tests[r]; +} +function restartAction() { + var r = transitions[sceneIdx]; + return tests[r]; +} + +var ActionDemo = nodes.Layer.extend({ + title: 'No title', + subtitle: null, + + init: function () { + ActionDemo.superclass.init.call(this); + + this.set('isMouseEnabled', true); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + var grossini = nodes.Sprite.create({file: module.dirname + "/resources/grossini.png", + rect: new geo.Rect(0, 0, 85, 121)}); + var tamara = nodes.Sprite.create({file: module.dirname + "/resources/grossinis_sister1.png", + rect: new geo.Rect(0, 0, 52, 139)}); + var kathia = nodes.Sprite.create({file: module.dirname + "/resources/grossinis_sister2.png", + rect: new geo.Rect(0, 0, 56, 138)}); + this.set('grossini', grossini); + this.set('tamara', tamara); + this.set('kathia', kathia); + + this.addChild({child: grossini, z: 1, tag: kTagSprite1}); + this.addChild({child: tamara, z: 2, tag: kTagSprite2}); + this.addChild({child: kathia, z: 3, tag: kTagSprite3}); + + grossini.set('position', ccp(s.width/2, s.height/3)); + tamara.set('position', ccp(s.width/2, 2*s.height/3)); + kathia.set('position', ccp(s.width/2, s.height/2)); + + var label = nodes.Label.create({string: this.get('title'), fontName: 'Arial', fontSize: 26}); + this.addChild({child: label, z: 1}); + label.set('position', ccp(s.width / 2, s.height - 50)); + + + var subtitle = this.get('subtitle'); + if (subtitle) { + var l = nodes.Label.create({string: subtitle, fontName: "Thonburi", fontSize: 16}); + this.addChild({child: l, z: 1}); + l.set('position', ccp(s.width / 2, s.height - 80)); + } + + var item1 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/b1.png", selectedImage: module.dirname + "/resources/b2.png", callback: util.callback(this, 'backCallback')}); + var item2 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/r1.png", selectedImage: module.dirname + "/resources/r2.png", callback: util.callback(this, 'restartCallback')}); + var item3 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/f1.png", selectedImage: module.dirname + "/resources/f2.png", callback: util.callback(this, 'nextCallback')}); + + var menu = nodes.Menu.create({items: [item1, item2, item3]}); + + menu.set('position', ccp(0, 0)); + item1.set('position', ccp(s.width / 2 - 100, 30)); + item2.set('position', ccp(s.width / 2, 30)); + item3.set('position', ccp(s.width / 2 + 100, 30)); + this.addChild({child: menu}); + }, + + restartCallback: function () { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({child: restartAction().create()}); + + director.replaceScene(scene); + }, + + backCallback: function () { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({child: backAction().create()}); + + director.replaceScene(scene); + }, + + nextCallback: function () { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({child: nextAction().create()}); + + director.replaceScene(scene); + }, + + alignSpritesLeft: function(numSprites) { + var s = cocos.Director.get('sharedDirector').get('winSize'); + + if (numSprites == 1) { + this.get('tamara').set('visible', false); + this.get('kathia').set('visible', false); + this.get('grossini').set('position', ccp(60, s.height/2)); + } else if (numSprites == 2) { + this.get('kathia').set('position', ccp(60, s.height/3)); + this.get('tamara').set('position', ccp(60, 2*s.height/3)); + this.get('grossini').set('visible', false); + } else if (numSprites == 3) { + this.get('grossini').set('position', ccp(60, s.height/2)); + this.get('tamara').set('position', ccp(60, 2*s.height/3)); + this.get('kathia').set('position', ccp(60, s.height/3)); + } + }, + + centerSprites: function(numSprites) { + var s = cocos.Director.get('sharedDirector').get('winSize'); + + if (numSprites == 1) { + this.get('tamara').set('visible', false); + this.get('kathia').set('visible', false); + this.get('grossini').set('position', ccp(s.width/2, s.height/2)); + } else if (numSprites == 2) { + this.get('kathia').set('position', ccp(s.width/3, s.height/2)); + this.get('tamara').set('position', ccp(2*s.width/3, s.height/2)); + this.get('grossini').set('visible', false); + } else if (numSprites == 3) { + this.get('grossini').set('position', ccp(s.width/2, s.height/2)); + this.get('tamara').set('position', ccp(2*s.width/3, s.height/2)); + this.get('kathia').set('position', ccp(s.width/3, s.height/2)); + } + }, + + addNewSprite: function (point, tag) { + var idx = Math.floor(Math.random() * 1400 / 100), + x = (idx % 5) * 85, + y = (idx % 3) * 121; + + var sprite = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: new geo.Rect(x, y, 85, 121)}); + this.addChild({child: sprite, z: 0, tag: tag}); + sprite.set('position', ccp(point.x, point.y)); + + return sprite; + } +}); + +tests.Manual = ActionDemo.extend(/** @lends Manual.prototype# */{ + title: 'Manual Transformation', + subtitle: '', + + onEnter: function() { + tests.Manual.superclass.onEnter.call(this); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + this.get('tamara').set('scale', ccp(2.5, -1.0)); + this.get('tamara').set('position', ccp(100, 70)); + this.get('tamara').set('opacity', 128); + + this.get('grossini').set('rotation', 120); + this.get('grossini').set('position', ccp(s.width/2, s.height/2)); + } +}); + +/** + * @class + * + * Example Move Action + */ +tests.Move = ActionDemo.extend(/** @lends Move.prototype# */{ + title: 'MoveTo / MoveBy', + subtitle: '', + + onEnter: function() { + tests.Move.superclass.onEnter.call(this); + + this.centerSprites(3); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + var actionTo = actions.MoveTo.create({duration: 2, position: ccp(s.width-40, s.height-40)}); + var actionBy = actions.MoveBy.create({duration: 2, position: ccp(80, 80)}); + var actionByBack = actionBy.reverse(); + + this.get('tamara').runAction(actionTo); + this.get('grossini').runAction(actions.Sequence.create({actions: [actionBy, actionByBack]})); + this.get('kathia').runAction(actions.MoveTo.create({duration: 1, position: ccp(40, 40)})); + } +}); + +/** + * @class + * + * Example Jump Action + */ +tests.Jump = ActionDemo.extend(/** @lends Jump.prototype# */{ + title: 'JumpTo / JumpBy', + subtitle: '', + + onEnter: function() { + tests.Jump.superclass.onEnter.call(this); + + var action, actionBack, seq; + var rand = Math.random(); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + var action1 = actions.JumpTo.create({duration: 2, delta: ccp(s.width/2, 300), height: 50, jumps: 4}); + var action2 = actions.JumpBy.create({duration: 2, delta: ccp(300, 0), height: 50, jumps: 4}); + var action3 = actions.JumpBy.create({duration: 2, delta: ccp(0, 0), height: 80, jumps: 4}); + actionBack = action2.reverse(); + + this.getChild({tag: kTagSprite1}).runAction(action1); + this.getChild({tag: kTagSprite2}).runAction(actions.Sequence.create({actions: [action2, actionBack]})); + this.getChild({tag: kTagSprite3}).runAction(actions.RepeatForever.create(action3)); + } +}); + +/** + * @class + * + * Example Bezier Action + */ +tests.Bezier = ActionDemo.extend(/** @lends Bezier.prototype# */{ + title: 'BezierBy / BezierTo', + subtitle: '', + + onEnter: function() { + tests.Bezier.superclass.onEnter.call(this); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + // this.alignSpritesLeft(); + + var bezier = new geo.BezierConfig(); + bezier.controlPoint1 = ccp(0, s.height/2); + bezier.controlPoint2 = ccp(300, -s.height/2); + bezier.endPosition = ccp(300,100); + + var bezierForward = actions.BezierBy.create({duration: 3, bezier: bezier}); + var bezierBack = bezierForward.reverse(); + var seq = actions.Sequence.create({actions: [bezierForward, bezierBack]}); + + this.get('tamara').set('position', ccp(80, 160)); + var bezier2 = new geo.BezierConfig(); + bezier2.controlPoint1 = ccp(100, s.height/2); + bezier2.controlPoint2 = ccp(200, -s.height/2); + bezier2.endPosition = ccp(240,160); + + var bezierTo1 = actions.BezierTo.create({duration: 2, bezier: bezier2}); + + this.get('kathia').set('position', ccp(400, 160)); + var bezierTo2 = actions.BezierTo.create({duration: 2, bezier: bezier2}); + + this.get('grossini').runAction(actions.RepeatForever.create(seq)); + this.get('tamara').runAction(bezierTo1); + this.get('kathia').runAction(bezierTo2); + } +}); + +/** + * @class + * + * Example Blink Action + */ +tests.Blink = ActionDemo.extend(/** @lends Blink.prototype# */{ + title: 'Blink', + subtitle: '', + + onEnter: function() { + tests.Blink.superclass.onEnter.call(this); + + this.centerSprites(2); + + this.get('tamara').runAction(actions.Blink.create({duration: 2, blinks: 10})); + this.get('kathia').runAction(actions.Blink.create({duration: 2, blinks: 5})); + } +}); + + +/** + * @class + * + * Example Sequence Action + */ +tests.Sequence = ActionDemo.extend(/** @lends Sequence.prototype# */{ + title: 'Sequence: Move + Rotate', + subtitle: '', + + onEnter: function() { + tests.Sequence.superclass.onEnter.call(this); + + this.alignSpritesLeft(1); + + var action = actions.Sequence.create({actions: [ + actions.MoveBy.create({duration: 2, position: ccp(240, 0)}), + actions.RotateBy.create({duration: 2, angle: 540}) + ]}); + this.get('grossini').runAction(action); + } +}); + +/** + * @class + * + * Example Sequence2 Action + */ +tests.Sequence2 = ActionDemo.extend(/** @lends Sequence2.prototype# */{ + title: 'Sequence of InstantActions', + subtitle: '', + + onEnter: function() { + tests.Sequence2.superclass.onEnter.call(this); + + this.alignSpritesLeft(1); + this.get('grossini').set('position', ccp(200, 200)); + + var action = actions.Sequence.create({actions: [ + actions.MoveBy.create({duration: 1, position: ccp(100, 0)}), + actions.CallFunc.create({target: this, method: 'callback1'}), + actions.CallFunc.create({target: this, method: 'callback2'}), + actions.CallFunc.create({target: this, method: 'callback3'}) + ]}); + this.get('grossini').runAction(action); + }, + + callback1: function(target) { + var s = cocos.Director.get('sharedDirector').get('winSize'); + var label = cocos.nodes.Label.create({string: "callback 1 called", fontName: 'Marker Felt', fontSize: 16}); + label.set('position', ccp(s.width / 4, s.height / 2)); + this.addChild({child: label}); + }, + + callback2: function(target) { + var s = cocos.Director.get('sharedDirector').get('winSize'); + var label = cocos.nodes.Label.create({string: "callback 2 called", fontName: 'Marker Felt', fontSize: 16}); + label.set('position', ccp(s.width / 4*2, s.height / 2)); + this.addChild({child: label}); + }, + + callback3: function(target) { + var s = cocos.Director.get('sharedDirector').get('winSize'); + var label = cocos.nodes.Label.create({string: "callback 3 called", fontName: 'Marker Felt', fontSize: 16}); + label.set('position', ccp(s.width / 4*3, s.height / 2)); + this.addChild({child: label}); + } +}); + +/** + * @class + * + * Example Spawn Action + */ +tests.Spawn = ActionDemo.extend(/** @lends Spawn.prototype# */{ + title: 'Spawn: Jump + Rotate', + subtitle: '', + + onEnter: function() { + tests.Spawn.superclass.onEnter.call(this); + + this.alignSpritesLeft(1); + var action = actions.Spawn.initWithActions({actions: [ + actions.JumpBy.create({duration: 2, delta: ccp(300, 0), height: 50, jumps: 4}), + actions.RotateBy.create({duration: 2, angle: 720}) + ]}); + this.getChild({tag: kTagSprite1}).runAction(action); + } +}); + +/** + * @class + * + * Example Reverse Action + */ +tests.Reverse = ActionDemo.extend(/** @lends Reverse.prototype# */{ + title: 'Reverse an action', + subtitle: '', + + onEnter: function() { + tests.Reverse.superclass.onEnter.call(this); + + this.alignSpritesLeft(1); + + var jump = actions.JumpBy.create({duration: 2, delta: ccp(300, 0), height: 50, jumps: 4}); + var action = actions.Sequence.create({actions: [jump, jump.reverse()]}); + + this.get('grossini').runAction(action); + } +}); + +/** + * @class + * + * Example Delay Action + */ +tests.Delay = ActionDemo.extend(/** @lends Delay.prototype# */{ + title: 'DelayTime: m + delay + m', + subtitle: '', + + onEnter: function() { + tests.Delay.superclass.onEnter.call(this); + + this.alignSpritesLeft(1); + + var move = actions.MoveBy.create({duration: 1, position: ccp(150, 0)}); + var action = actions.Sequence.create({actions: [move, + actions.DelayTime.create({duration: 2}), + move]}); + + this.get('grossini').runAction(action); + } +}); + +/** + * @class + * + * Example ReverseSequence Action + */ +tests.ReverseSequence = ActionDemo.extend(/** @lends ReverseSequence.prototype# */{ + title: 'Reverse a sequence', + subtitle: '', + + onEnter: function() { + tests.ReverseSequence.superclass.onEnter.call(this); + + this.alignSpritesLeft(1); + + var move1 = actions.MoveBy.create({duration: 1, position: ccp(250, 0)}); + var move2 = actions.MoveBy.create({duration: 1, position: ccp(0, 50)}); + var seq = actions.Sequence.create({actions: [move1, move2, move1.reverse()]}); + var action = actions.Sequence.create({actions: [seq, seq.reverse()]}); + + this.get('grossini').runAction(action); + } +}); + +/** + * @class + * + * Example Repeat Action + */ +tests.Repeat = ActionDemo.extend(/** @lends Repeat.prototype# */{ + title: 'Repeat / RepeatForever actions', + subtitle: '', + + onEnter: function() { + tests.Repeat.superclass.onEnter.call(this); + + this.alignSpritesLeft(2); + + var a1 = actions.MoveBy.create({duration: 1, position: ccp(150, 0)}); + var action1 = actions.Repeat.create({action: actions.Sequence.create({actions: [ + actions.Place.create({position: ccp(60, 60)}), + a1 + ]}), + times: 3}); + + var action2 = actions.RepeatForever.create(actions.Sequence.create({actions: [ + a1.copy(), a1.reverse()]})); + + this.get('kathia').runAction(action1); + this.get('tamara').runAction(action2); + } +}); + +/** + * @class + * + * Example RepeatForever Action + */ +tests.RepeatForever = ActionDemo.extend(/** @lends RepeatForever.prototype# */{ + title: 'CallFunc + RepeatForever', + subtitle: '', + + onEnter: function() { + tests.RepeatForever.superclass.onEnter.call(this); + + this.centerSprites(1); + + this.get('grossini').runAction(actions.Sequence.create({actions: [ + actions.DelayTime.create({duration: 1}), + actions.CallFunc.create({target: this, method: 'repeatForever'}) + ]})); + }, + + repeatForever: function(target) { + target.runAction(actions.RepeatForever.create(actions.RotateBy.create({duration: 1, angle: 360}))); + } +}); + +/** + * @class + * + * Example RotateToRepeat Action + */ +tests.RotateToRepeat = ActionDemo.extend(/** @lends RotateToRepeat.prototype# */{ + title: 'Repeat/RepeatForever + RotateTo', + subtitle: 'You should see smooth movements', + + onEnter: function() { + tests.RotateToRepeat.superclass.onEnter.call(this); + + this.centerSprites(2); + + var act1 = actions.RotateTo.create({duration: 1, angle: 90}); + var act2 = actions.RotateTo.create({duration: 1, angle: 0}); + var seq = actions.Sequence.create({actions: [act1, act2]}); + var rep1 = actions.RepeatForever.create(seq); + var rep2 = actions.Repeat.create({action: seq, times: 10}); + + this.get('tamara').runAction(rep1); + this.get('kathia').runAction(rep2); + } +}); + +/** + * @class + * + * Example RotateJerk Action + */ +tests.RotateJerk = ActionDemo.extend(/** @lends RotateJerk.prototype# */{ + title: 'RepeatForever / Repeat + RotateTo', + subtitle: 'You should see smooth movements', + + onEnter: function() { + tests.RotateJerk.superclass.onEnter.call(this); + + this.centerSprites(2); + + var seq = actions.Sequence.create({actions: [ + actions.RotateTo.create({duration: 0.5, angle :-20}), + actions.RotateTo.create({duration: 0.5, angle: 20}) + ]}); + var rep1 = actions.Repeat.create({action: seq, times: 10}); + var rep2 = actions.RepeatForever.create(seq); + this.get('tamara').runAction(rep1); + this.get('kathia').runAction(rep2); + } +}); + +/** + * @class + * + * Example ReverseSequence2 Action + */ +tests.ReverseSequence2 = ActionDemo.extend(/** @lends ReverseSequence2.prototype# */{ + title: 'Reverse sequence 2', + subtitle: '', + + onEnter: function() { + tests.ReverseSequence2.superclass.onEnter.call(this); + + this.alignSpritesLeft(2); + + // Sequence should work both with IntervalAction and InstantActions + var move1 = actions.MoveBy.create({duration: 1, position: ccp(250, 0)}); + var move2 = actions.MoveBy.create({duration: 1, position: ccp(0, 50)}); + var tog1 = actions.ToggleVisibility.create(); + var tog2 = actions.ToggleVisibility.create(); + var seq = actions.Sequence.create({actions: [move1, tog1, move2, tog2, move1.reverse()]}); + var action = actions.Repeat.create({action: actions.Sequence.create({actions: [ + seq, seq.reverse() + ]}), + times: 3}); + this.get('kathia').runAction(action); + + // Also test that the reverse of Hide is Show, and vice-versa + var move_t = actions.MoveBy.create({duration: 1, position: ccp(100, 0)}); + var move_t2 = actions.MoveBy.create({duration: 1, position: ccp(50, 0)}); + var hide = actions.Hide.create(); + var seq_t = actions.Sequence.create({actions: [ + move_t, hide, move_t2]}); + var seq_back = seq_t.reverse(); + this.get('tamara').runAction(actions.Sequence.create({actions: [ + seq_t, seq_back]})); + } +}); + +/** + * @class + * + * Example Speed Action + */ +tests.Speed = ActionDemo.extend(/** @lends Speed.prototype# */{ + title: 'Speed', + subtitle: '', + + onEnter: function() { + tests.Speed.superclass.onEnter.call(this); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + this.alignSpritesLeft(3); + // rotate and jump + var jump1 = actions.JumpBy.create({duration: 4, delta: ccp(-s.width+80, 0), height: 100, jumps: 4}); + var jump2 = jump1.reverse(); + var rot1 = actions.RotateBy.create({duration: 4, angle: 720}); + var rot2 = rot1.reverse(); + + var seq3_1 = actions.Sequence.create({actions: [jump2, jump1]}); + var seq3_2 = actions.Sequence.create({actions: [rot1, rot2]}); + var spawn = actions.Spawn.create({one: seq3_1, two: seq3_2}); + var action = actions.Speed.create({action: actions.RepeatForever.create(spawn), speed: 1.0}); + action.set('tag', kTagAction1); + + var action2 = action.copy(); + var action3 = action.copy(); + action2.set('tag', kTagAction1); + action3.set('tag', kTagAction1); + + this.getChild({tag: kTagSprite1}).runAction(action2); + this.getChild({tag: kTagSprite2}).runAction(action3); + this.getChild({tag: kTagSprite3}).runAction(action); + + Scheduler.get('sharedScheduler').schedule({target: this, method: 'update', interval: 1.0, paused: !this.get('isRunning')}); + }, + + update: function(t) { + var action1 = this.getChild({tag: kTagSprite1}).getAction({tag: kTagAction1}); + var action2 = this.getChild({tag: kTagSprite2}).getAction({tag: kTagAction1}); + var action3 = this.getChild({tag: kTagSprite3}).getAction({tag: kTagAction1}); + + action1.setSpeed(Math.random() * 2); + action2.setSpeed(Math.random() * 2); + action3.setSpeed(Math.random() * 2); + } +}); + +tests.Follow = ActionDemo.extend(/** @lends Follow.prototype# */{ + title: 'Follow action', + subtitle: 'The sprite should be centered, even though it is being moved', + + onEnter: function() { + tests.Follow.superclass.onEnter.call(this); + + this.centerSprites(1); + var s = cocos.Director.get('sharedDirector').get('winSize'); + + this.get('grossini').set('position', ccp(-200, s.height/2)); + + var move = actions.MoveBy.create({duration: 2, position: ccp(s.width*3, 0)}); + var move_back = move.reverse(); + var seq = actions.Sequence.create({actions: [move, move_back]}); + var rep = actions.RepeatForever.create(seq); + + this.get('grossini').runAction(rep); + + this.runAction(actions.Follow.create({target: this.get('grossini'), + worldBoundary: new geo.Rect(0, 0, s.width*2-100, s.height)})); + + }, + + draw: function(ctxt) { + var s = cocos.Director.get('sharedDirector').get('winSize'); + + var x = s.width*2 - 100, + y = s.height; + + var vertices = [ccp(x-5, 5), ccp(x-5, y-5), ccp(5, y-5)]; + ctxt.beginPath(); + ctxt.moveTo(5, 5); + for (var i=0; i 10) { + this.dir = -1; + } + + z += this.dir * 3; + + this.reorderChild({child: sprite, z: z}); + } +}); + +/** + * @class + * + * Example using AnimationCache and loading from a Zwoptex .plist file + */ +tests.AnimationCache = SpriteDemo.extend(/** @lends AnimationCache.prototype# */{ + title: 'AnimationCache', + subtitle: 'Sprite should be animated', + + init: function () { + tests.AnimationCache.superclass.init.call(this); + + var frameCache = cocos.SpriteFrameCache.get('sharedSpriteFrameCache'), + animCache = cocos.AnimationCache.get('sharedAnimationCache'); + + frameCache.addSpriteFrames({file: module.dirname + '/resources/animations/grossini.plist'}); + frameCache.addSpriteFrames({file: module.dirname + '/resources/animations/grossini_gray.plist'}); + frameCache.addSpriteFrames({file: module.dirname + '/resources/animations/grossini_blue.plist'}); + + + // create "dance" animation + var animFrames = [], + frame, + i; + for (i = 1; i < 15; i++) { + frame = frameCache.getSpriteFrame({name: 'grossini_dance_' + (i >= 10 ? i : '0' + i) + '.png'}); + animFrames.push(frame); + } + + var animation = cocos.Animation.create({frames: animFrames, delay: 0.2}); + + // Add an animation to the Cache + animCache.addAnimation({animation: animation, name: 'dance'}); + + + // create animation "dance gray" + animFrames = []; + for (i = 1; i < 15; i++) { + frame = frameCache.getSpriteFrame({name: 'grossini_dance_gray_' + (i >= 10 ? i : '0' + i) + '.png'}); + animFrames.push(frame); + } + + animation = cocos.Animation.create({frames: animFrames, delay: 0.2}); + + // Add an animation to the Cache + animCache.addAnimation({animation: animation, name: 'dance_gray'}); + + + // create animation "dance blue" + animFrames = []; + for (i = 1; i < 4; i++) { + frame = frameCache.getSpriteFrame({name: 'grossini_blue_0' + i + '.png'}); + animFrames.push(frame); + } + + animation = cocos.Animation.create({frames: animFrames, delay: 0.2}); + + // Add an animation to the Cache + animCache.addAnimation({animation: animation, name: 'dance_blue'}); + + + var normal = animCache.getAnimation({name: 'dance'}), + dance_gray = animCache.getAnimation({name: 'dance_gray'}), + dance_blue = animCache.getAnimation({name: 'dance_blue'}); + + var animN = actions.Animate.create({animation: normal}), + animG = actions.Animate.create({animation: dance_gray}), + animB = actions.Animate.create({animation: dance_blue}); + + var seq = actions.Sequence.create({actions: [animN, animG, animB]}); + + // create an sprite without texture + var grossini = nodes.Sprite.create(); + + var winSize = cocos.Director.get('sharedDirector').get('winSize'); + + grossini.set('position', ccp(winSize.width / 2, winSize.height / 2)); + + this.addChild({child: grossini}); + + + // run the animation + grossini.runAction(seq); + } +}); + +tests.SpriteColorOpacity = SpriteDemo.extend(/** @lends SpriteColorOpacity.prototype# */{ + title: "Sprite: Opacity", + + init: function () { + tests.SpriteColorOpacity.superclass.init.call(this); + + + var sprite1 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 0, 121 * 1, 85, 121)}); + var sprite2 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 1, 121 * 1, 85, 121)}); + var sprite3 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 2, 121 * 1, 85, 121)}); + var sprite4 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 3, 121 * 1, 85, 121)}); + + var sprite5 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 0, 121 * 1, 85, 121)}); + var sprite6 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 1, 121 * 1, 85, 121)}); + var sprite7 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 2, 121 * 1, 85, 121)}); + var sprite8 = nodes.Sprite.create({file: module.dirname + "/resources/grossini_dance_atlas.png", rect: geo.rectMake(85 * 3, 121 * 1, 85, 121)}); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + sprite1.set('position', ccp((s.width / 5) * 1, (s.height / 3) * 1)); + sprite2.set('position', ccp((s.width / 5) * 2, (s.height / 3) * 1)); + sprite3.set('position', ccp((s.width / 5) * 3, (s.height / 3) * 1)); + sprite4.set('position', ccp((s.width / 5) * 4, (s.height / 3) * 1)); + + sprite5.set('position', ccp((s.width / 5) * 1, (s.height / 3) * 2)); + sprite6.set('position', ccp((s.width / 5) * 2, (s.height / 3) * 2)); + sprite7.set('position', ccp((s.width / 5) * 3, (s.height / 3) * 2)); + sprite8.set('position', ccp((s.width / 5) * 4, (s.height / 3) * 2)); + + var action = actions.FadeIn.create({duration: 3}), + actionBack = action.reverse(), + fade = actions.RepeatForever.create(actions.Sequence.create({actions: [action, actionBack]})); + + /* + id tintred = [CCTintBy actionWithDuration:2 red:0 green:-255 blue:-255]; + id tintred_back = [tintred reverse]; + id red = [CCRepeatForever actionWithAction: [CCSequence actions: tintred, tintred_back, nil]]; + + id tintgreen = [CCTintBy actionWithDuration:2 red:-255 green:0 blue:-255]; + id tintgreen_back = [tintgreen reverse]; + id green = [CCRepeatForever actionWithAction: [CCSequence actions: tintgreen, tintgreen_back, nil]]; + + id tintblue = [CCTintBy actionWithDuration:2 red:-255 green:-255 blue:0]; + id tintblue_back = [tintblue reverse]; + id blue = [CCRepeatForever actionWithAction: [CCSequence actions: tintblue, tintblue_back, nil]]; + */ + + + /* + [sprite5 runAction:red]; + [sprite6 runAction:green]; + [sprite7 runAction:blue]; + */ + sprite8.runAction(fade); + + // late add: test dirtyColor and dirtyPosition + this.addChild({child: sprite1, z: 0, tag: kTagSprite1}); + this.addChild({child: sprite2, z: 0, tag: kTagSprite2}); + this.addChild({child: sprite3, z: 0, tag: kTagSprite3}); + this.addChild({child: sprite4, z: 0, tag: kTagSprite4}); + this.addChild({child: sprite5, z: 0, tag: kTagSprite5}); + this.addChild({child: sprite6, z: 0, tag: kTagSprite6}); + this.addChild({child: sprite7, z: 0, tag: kTagSprite7}); + this.addChild({child: sprite8, z: 0, tag: kTagSprite8}); + + + cocos.Scheduler.get('sharedScheduler').schedule({target: this, method: this.removeAndAddSprite, interval: 2}); + }, + + removeAndAddSprite: function () { + var sprite = this.getChild({tag: kTagSprite5}); + + this.removeChild({child: sprite, cleanup: false}); + this.addChild({child: sprite, z: 0, tag: kTagSprite5}); + } +}); + + +exports.main = function () { + // Initialise test + var director = cocos.Director.get('sharedDirector'); + + director.attachInView(document.getElementById('cocos2d-tests')); + director.set('displayFPS', true); + + events.addListener(director, 'ready', function (director) { + var scene = nodes.Scene.create(); + scene.addChild({child: nextAction().create()}); + director.replaceScene(scene); + }); + + director.runPreloadScene(); +}; diff --git a/tests/src/cocos2d/TileMapTest.js b/tests/src/cocos2d/TileMapTest.js new file mode 100644 index 0000000..54d8748 --- /dev/null +++ b/tests/src/cocos2d/TileMapTest.js @@ -0,0 +1,280 @@ +/*globals module exports resource require FLIP_Y_AXIS console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + Texture2D = require('cocos2d/Texture2D').Texture2D, + cocos = require('cocos2d'), + nodes = cocos.nodes, + events = require('events'), + actions = cocos.actions, + geo = require('geometry'), + ccp = geo.ccp; + +var sceneIdx = -1; +var transitions = [ + "TMXReadWriteTest", + "TMXOrthoTest2", + "TMXOrthoObjectsTest", + "TMXIsoTest" +]; + +var tests = {}; + + +var kTagTileMap = 1; + +function nextAction() { + sceneIdx++; + sceneIdx = sceneIdx % transitions.length; + + var r = transitions[sceneIdx]; + return tests[r]; +} +function backAction() { + sceneIdx--; + if (sceneIdx < 0) { + sceneIdx += transitions.length; + } + + var r = transitions[sceneIdx]; + return tests[r]; +} +function restartAction() { + var r = transitions[sceneIdx]; + return tests[r]; +} + +var TileDemo = nodes.Layer.extend({ + title: 'No title', + subtitle: null, + + init: function () { + TileDemo.superclass.init.call(this); + + this.set('isMouseEnabled', true); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + var label = nodes.Label.create({string: this.get('title'), fontName: 'Arial', fontSize: 26}); + this.addChild({child: label, z: 1}); + label.set('position', ccp(s.width / 2, s.height - 50)); + + + var subtitle = this.get('subtitle'); + if (subtitle) { + var l = nodes.Label.create({string: subtitle, fontName: "Thonburi", fontSize: 16}); + this.addChild({child: l, z: 1}); + l.set('position', ccp(s.width / 2, s.height - 80)); + } + + + var item1 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/b1.png", selectedImage: module.dirname + "/resources/b2.png", callback: util.callback(this, 'backCallback')}); + var item2 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/r1.png", selectedImage: module.dirname + "/resources/r2.png", callback: util.callback(this, 'restartCallback')}); + var item3 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/f1.png", selectedImage: module.dirname + "/resources/f2.png", callback: util.callback(this, 'nextCallback')}); + + var menu = nodes.Menu.create({items: [item1, item2, item3]}); + + menu.set('position', ccp(0, 0)); + item1.set('position', ccp(s.width / 2 - 100, 30)); + item2.set('position', ccp(s.width / 2, 30)); + item3.set('position', ccp(s.width / 2 + 100, 30)); + this.addChild({child: menu, z: 1}); + }, + + mouseDragged: function (event) { + var node = this.getChild({tag: kTagTileMap}); + var currentPos = node.get('position'); + node.set('position', geo.ccpAdd(currentPos, ccp(event.deltaX, event.deltaY))); + return true; + }, + + restartCallback: function () { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({child: restartAction().create()}); + + director.replaceScene(scene); + }, + + backCallback: function () { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({child: backAction().create()}); + + director.replaceScene(scene); + }, + + nextCallback: function () { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({child: nextAction().create()}); + + director.replaceScene(scene); + } +}); + + +tests.TMXOrthoTest2 = TileDemo.extend({ + title: 'Tile Map Test', + subtitle: 'drag screen', + + init: function () { + tests.TMXOrthoTest2.superclass.init.call(this); + + var map = nodes.TMXTiledMap.create({file: module.dirname + "/resources/TileMaps/orthogonal-test1.tmx"}); + this.addChild({child: map, z: 0, tag: kTagTileMap}); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + map.runAction(actions.ScaleBy.create({duration: 2, scale: 0.5})); + } +}); + + +tests.TMXIsoTest = TileDemo.extend({ + title: 'TMX Isometric test 0', + + init: function () { + tests.TMXIsoTest.superclass.init.call(this); + + /* + CCLayerColor *color = [CCLayerColor layerWithColor:ccc4(64,64,64,255)]; + [self addChild:color z:-1]; + */ + + var map = nodes.TMXTiledMap.create({file: module.dirname + "/resources/TileMaps/iso-test.tmx"}); + this.addChild({child: map, z: 0, tag: kTagTileMap}); + + // move map to the center of the screen + var ms = map.get('mapSize'), + ts = map.get('tileSize'); + + map.set('position', ccp(-ms.width * ts.width / 2, -ms.height * ts.height / 2)); + + //map.runAction(actions.MoveTo.create({duration: 1.0, position: ccp(-ms.width * ts.width / 2, -ms.height * ts.height / 2)})); + } +}); + +tests.TMXOrthoObjectsTest = TileDemo.extend({ + title: 'TMX Ortho object test', + subtitle: 'You should see a white box around the 3 platforms', + + init: function () { + tests.TMXOrthoObjectsTest.superclass.init.call(this); + + var map = nodes.TMXTiledMap.create({file: module.dirname + "/resources/TileMaps/ortho-objects.tmx"}); + this.addChild({child: map, z: -1, tag: kTagTileMap}); + + var s = map.get('contentSize'); + + console.log("ContentSize: %f, %f", s.width, s.height); + console.log("----> Iterating over all the group objects"); + + var group = map.getObjectGroup({name: 'Object Group 1'}), + objs = group.get('objects'); + for (var i = 0, len = objs.length; i < len; i++) { + var obj = objs[i]; + console.log("Object: ", obj); + } + + console.log("----> Fetching 1 object by name"); + var platform = group.getObject({name: "platform"}); + console.log("platform: ", platform); + }, + + draw: function (ctx) { + var map = this.getChild({tag: kTagTileMap}), + group = map.getObjectGroup({name: 'Object Group 1'}), + objs = group.get('objects'); + + ctx.save(); + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 3; + ctx.beginPath(); + + if (FLIP_Y_AXIS) { + ctx.scale(1, -1); + ctx.translate(0, -1024); + } + + for (var i = 0, len = objs.length; i < len; i++) { + var obj = objs[i]; + + var x = obj.x, + y = obj.y, + width = obj.width, + height = obj.height; + + ctx.moveTo(x, y); + ctx.lineTo(x + width, y); + ctx.lineTo(x + width, y + height); + ctx.lineTo(x, y + height); + ctx.lineTo(x, y); + } + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + } +}); + +tests.TMXReadWriteTest = TileDemo.extend({ + title: 'TMX Read/Write test', + + init: function () { + tests.TMXReadWriteTest.superclass.init.call(this); + + var map = nodes.TMXTiledMap.create({file: module.dirname + "/resources/TileMaps/orthogonal-test2.tmx"}); + this.addChild({child: map, z: 0, tag: kTagTileMap}); + + + var s = map.get('contentSize'); + console.log("ContentSize: %f, %f", s.width, s.height); + + + var layer = map.getLayer({name: "Layer 0"}); + var tile0 = layer.tileAt(ccp(1, 63)), + tile1 = layer.tileAt(ccp(2, 63)), + tile2 = layer.tileAt(ccp(2, 62)); + + + tile0.set('anchorPoint', ccp(0.5, 0.5)); + tile1.set('anchorPoint', ccp(0.5, 0.5)); + tile2.set('anchorPoint', ccp(0.5, 0.5)); + + var move = actions.MoveBy.create({duration: 0.5, position: ccp(0, 160)}), + rotate = actions.RotateBy.create({duration: 2.0, angle: 360}), + scale = actions.ScaleBy.create({duration: 2.0, scale: 5}); + + + var seq0 = actions.Sequence.create({actions: [move, rotate, scale]}), /*, scale, opacity, fadein, scaleback, finish, nil];*/ + seq1 = seq0.copy(), + seq2 = seq0.copy(); + + tile0.runAction(seq0); + tile1.runAction(seq1); + tile2.runAction(seq2); + + } +}); + + +exports.main = function () { + // Initialise test + var director = cocos.Director.get('sharedDirector'); + + director.attachInView(document.getElementById('cocos2d-tests')); + director.set('displayFPS', true); + + events.addListener(director, 'ready', function (director) { + var scene = nodes.Scene.create(); + scene.addChild({child: nextAction().create()}); + + director.replaceScene(scene); + }); + + director.runPreloadScene(); +}; diff --git a/tests/src/cocos2d/TransitionTest.js b/tests/src/cocos2d/TransitionTest.js new file mode 100644 index 0000000..18415e3 --- /dev/null +++ b/tests/src/cocos2d/TransitionTest.js @@ -0,0 +1,245 @@ +/*globals module exports resource require FLIP_Y_AXIS console*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var util = require('util'), + Texture2D = require('cocos2d/Texture2D').Texture2D, + cocos = require('cocos2d'), + nodes = cocos.nodes, + events = require('events'), + actions = cocos.actions, + geo = require('geometry'), + ccp = geo.ccp; + +var sceneIdx = -1; +var transitions = [ + "TransitionRotoZoomTest", + "TransitionMoveInLTest", + "TransitionMoveInRTest", + "TransitionMoveInTTest", + "TransitionMoveInBTest", + "TransitionSlideInLTest", + "TransitionSlideInRTest", + "TransitionSlideInTTest", + "TransitionSlideInBTest"]; +var transObjects = [ + cocos.nodes.TransitionRotoZoom, + cocos.nodes.TransitionMoveInL, + cocos.nodes.TransitionMoveInR, + cocos.nodes.TransitionMoveInT, + cocos.nodes.TransitionMoveInB, + cocos.nodes.TransitionSlideInL, + cocos.nodes.TransitionSlideInR, + cocos.nodes.TransitionSlideInT, + cocos.nodes.TransitionSlideInB]; +var tests = {}; + +function nextAction() { + sceneIdx++; + sceneIdx = sceneIdx % transitions.length; + + var r = transitions[sceneIdx]; + return tests[r]; +} + +function backAction() { + sceneIdx--; + if (sceneIdx < 0) { + sceneIdx += transitions.length; + } + + var r = transitions[sceneIdx]; + return tests[r]; +} + + +function restartAction() { + var r = transitions[sceneIdx]; + return tests[r]; +} + + +var TransitionDemo = nodes.Layer.extend({ + title: '', + subtitle: null, + + init: function() { + TransitionDemo.superclass.init.call(this); + + this.set('isMouseEnabled', true); + + var s = cocos.Director.get('sharedDirector').get('winSize'); + + var label = nodes.Label.create({ + string: this.get('title'), + fontName: 'Arial', + fontSize: 26 + }); + this.addChild({ + child: label, + z: 1 + }); + label.set('position', ccp(s.width / 2, s.height - 50)); + + var subtitle = this.get('subtitle'); + if (subtitle) { + var l = nodes.Label.create({ + string: subtitle, + fontName: "Thonburi", + fontSize: 16 + }); + this.addChild({ + child: l, + z: 1 + }); + l.set('position', ccp(s.width / 2, s.height - 80)); + } + + var item1 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/b1.png", selectedImage: module.dirname + "/resources/b2.png", callback: util.callback(this, 'backCallback')}); + var item2 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/r1.png", selectedImage: module.dirname + "/resources/r2.png", callback: util.callback(this, 'restartCallback')}); + var item3 = nodes.MenuItemImage.create({normalImage: module.dirname + "/resources/f1.png", selectedImage: module.dirname + "/resources/f2.png", callback: util.callback(this, 'nextCallback')}); + + var menu = nodes.Menu.create({items: [item1, item2, item3]}); + + menu.set('position', ccp(0, 0)); + item1.set('position', ccp(s.width / 2 - 100, 30)); + item2.set('position', ccp(s.width / 2, 30)); + item3.set('position', ccp(s.width / 2 + 100, 30)); + this.addChild({child: menu, z: 1}); + }, + + restartCallback: function() { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({ + child: restartAction().create() + }); + + director.replaceScene(scene); + }, + + backCallback: function() { + var director = cocos.Director.get('sharedDirector'); + + var scene = nodes.Scene.create(); + scene.addChild({ + child: backAction().create() + }); + + director.replaceScene(transObjects[sceneIdx].create({duration: 1.5, + scene: scene})); + }, + + nextCallback: function() { + var director = cocos.Director.get('sharedDirector'); + var scene = nodes.Scene.create(); + scene.addChild({ + child: nextAction().create() + }); + var transIdx = (sceneIdx === 0) ? transObjects.length-1 : sceneIdx-1; + director.replaceScene(transObjects[transIdx].create({duration: 1.5, + scene: scene})); + } + +}); + + +tests.TransitionRotoZoomTest = TransitionDemo.extend({ + title: 'TransitionRotoZoom Test', + subtitle: 'rotates and zooms & reverse to next scene', + + init: function() { + tests.TransitionRotoZoomTest.superclass.init.call(this); + } +}); + +tests.TransitionMoveInLTest = TransitionDemo.extend({ + title: 'TransitionMoveInL Test', + subtitle: 'next scene moves in from the left', + + init: function() { + tests.TransitionMoveInLTest.superclass.init.call(this); + } +}); + +tests.TransitionMoveInRTest = TransitionDemo.extend({ + title: 'TransitionMoveInR Test', + subtitle: 'next scene moves in from the right', + + init: function() { + tests.TransitionMoveInLTest.superclass.init.call(this); + } +}); + +tests.TransitionMoveInTTest = TransitionDemo.extend({ + title: 'TransitionMoveInT Test', + subtitle: 'next scene moves in from the top', + + init: function() { + tests.TransitionMoveInTTest.superclass.init.call(this); + } +}); + +tests.TransitionMoveInBTest = TransitionDemo.extend({ + title: 'TransitionMoveInB Test', + subtitle: 'next scene moves in from the bottom', + + init: function() { + tests.TransitionMoveInBTest.superclass.init.call(this); + } +}); + +tests.TransitionSlideInLTest = TransitionDemo.extend({ + title: 'TransitionSlideInL Test', + subtitle: 'next scene pans in from the left', + + init: function() { + tests.TransitionSlideInLTest.superclass.init.call(this); + } +}); + +tests.TransitionSlideInRTest = TransitionDemo.extend({ + title: 'TransitionSlideInR Test', + subtitle: 'next scene pans in from the right', + + init: function() { + tests.TransitionSlideInRTest.superclass.init.call(this); + } +}); + +tests.TransitionSlideInTTest = TransitionDemo.extend({ + title: 'TransitionSlideInT Test', + subtitle: 'next scene slides in from the top', + + init: function() { + tests.TransitionSlideInTTest.superclass.init.call(this); + } +}); + +tests.TransitionSlideInBTest = TransitionDemo.extend({ + title: 'TransitionSlideInB Test', + subtitle: 'next scene slides in from the bottom', + + init: function() { + tests.TransitionSlideInBTest.superclass.init.call(this); + } +}); + +exports.main = function() { + // Initialise test + var director = cocos.Director.get('sharedDirector'); + + director.attachInView(document.getElementById('cocos2d-tests')); + director.set('displayFPS', true); + + events.addListener(director, 'ready', function(director) { + var scene = nodes.Scene.create(); + scene.addChild({ + child: nextAction().create() + }); + director.replaceScene(scene); + }); + + director.runPreloadScene(); +}; diff --git a/tests/cocos2d/main.js b/tests/src/cocos2d/main.js similarity index 100% rename from tests/cocos2d/main.js rename to tests/src/cocos2d/main.js diff --git a/tests/cocos2d/resources/TileMaps/fixed-ortho-test2.png b/tests/src/cocos2d/resources/TileMaps/fixed-ortho-test2.png similarity index 100% rename from tests/cocos2d/resources/TileMaps/fixed-ortho-test2.png rename to tests/src/cocos2d/resources/TileMaps/fixed-ortho-test2.png diff --git a/tests/src/cocos2d/resources/TileMaps/iso-test.png b/tests/src/cocos2d/resources/TileMaps/iso-test.png new file mode 100644 index 0000000..bb6327f Binary files /dev/null and b/tests/src/cocos2d/resources/TileMaps/iso-test.png differ diff --git a/tests/src/cocos2d/resources/TileMaps/iso-test.tmx b/tests/src/cocos2d/resources/TileMaps/iso-test.tmx new file mode 100644 index 0000000..d46c585 --- /dev/null +++ b/tests/src/cocos2d/resources/TileMaps/iso-test.tmx @@ -0,0 +1,17 @@ + + + + + + + + + H4sIAAAAAAAAA+3DwQkAAAwDoYPsv3PH6EfBVVNVVVVVVVVVVVVVVVVVVVVfH73hYN0AQAAA + + + + + H4sIAAAAAAAAA+2Y2Y7DIAxFeeD/v3nEQ6UMYvGW4Gt8pKptAgnXZrFdSpLQqKcHkCTJJ9Tyf73X7js6vc6vdJ+27+3vP0m/5m4DQfubPkLxv+UYR/ssgg0sqN2nvz5rG4Gd5t42ddIuGhRtUWww0kDVFsEGKw1UG6AzswHFv4j6OWPe2QBN/26+c9YC4vrXrOlT+agVWn8h+vsHd+yaM8Er3LHP6k/ISG2APvdX/2d90OP9le8ixjVPqPnsqj8y1Hglao7PiekjrPURXBuUwfX+vmc4a3w3D3bv8GgPie8o9lrVBz3ZQbKfc2o9q3se7CA90yk5PkItSDpGS32n5wJXh1VeyG3zJhw/ScZKPSNOYrWnrWII7fvfRlvref7mxgoe9DcoedCs3+o5s3bUe18iqWFYtPOiv2G1z3PmgId9UArXr9J90ivSWJrzHFS0+RQ6nHwhov4Gcp3Agqi6qET2LRVNLh0BSf0wEpo6QgSeZ9xt2hvRzzgKN2tPkiRJEg1/QULzBABAAAA= + + + diff --git a/tests/src/cocos2d/resources/TileMaps/ortho-objects.tmx b/tests/src/cocos2d/resources/TileMaps/ortho-objects.tmx new file mode 100644 index 0000000..17fec3d --- /dev/null +++ b/tests/src/cocos2d/resources/TileMaps/ortho-objects.tmx @@ -0,0 +1,21 @@ + + + + + + + + + H4sIAAAAAAAAA+3DsQkAIAwAsAriY/7/k6NQXBx00AQSAQAA8Iea3tZTprb4mrLxhAFhdCAKABAAAA== + + + + + + + + + + + + diff --git a/tests/cocos2d/resources/TileMaps/ortho-test1.png b/tests/src/cocos2d/resources/TileMaps/ortho-test1.png similarity index 100% rename from tests/cocos2d/resources/TileMaps/ortho-test1.png rename to tests/src/cocos2d/resources/TileMaps/ortho-test1.png diff --git a/tests/src/cocos2d/resources/TileMaps/orthogonal-test1.tmx b/tests/src/cocos2d/resources/TileMaps/orthogonal-test1.tmx new file mode 100644 index 0000000..d8c693b --- /dev/null +++ b/tests/src/cocos2d/resources/TileMaps/orthogonal-test1.tmx @@ -0,0 +1,31 @@ + + + + + + + + H4sIAAAAAAAAA9XMzQpAQBhG4cnfwsK/sJVBuf/7c9Sn3o0aWXnrSTNz4ty/N4iQTSJkBUpUdp4futa+m4gRIUGKTNq7X7Fbr2usud48Frv3osaBER166/OX/Zf/n+tha6FAAgAA + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/cocos2d/resources/TileMaps/orthogonal-test1.tsx b/tests/src/cocos2d/resources/TileMaps/orthogonal-test1.tsx similarity index 100% rename from tests/cocos2d/resources/TileMaps/orthogonal-test1.tsx rename to tests/src/cocos2d/resources/TileMaps/orthogonal-test1.tsx diff --git a/tests/cocos2d/resources/TileMaps/orthogonal-test2.tmx b/tests/src/cocos2d/resources/TileMaps/orthogonal-test2.tmx similarity index 100% rename from tests/cocos2d/resources/TileMaps/orthogonal-test2.tmx rename to tests/src/cocos2d/resources/TileMaps/orthogonal-test2.tmx diff --git a/tests/cocos2d/resources/TileMaps/orthogonal-test4.tmx b/tests/src/cocos2d/resources/TileMaps/orthogonal-test4.tmx similarity index 100% rename from tests/cocos2d/resources/TileMaps/orthogonal-test4.tmx rename to tests/src/cocos2d/resources/TileMaps/orthogonal-test4.tmx diff --git a/tests/cocos2d/resources/animations/dragon_animation.png b/tests/src/cocos2d/resources/animations/dragon_animation.png similarity index 100% rename from tests/cocos2d/resources/animations/dragon_animation.png rename to tests/src/cocos2d/resources/animations/dragon_animation.png diff --git a/tests/cocos2d/resources/animations/grossini.plist b/tests/src/cocos2d/resources/animations/grossini.plist similarity index 100% rename from tests/cocos2d/resources/animations/grossini.plist rename to tests/src/cocos2d/resources/animations/grossini.plist diff --git a/tests/cocos2d/resources/animations/grossini.png b/tests/src/cocos2d/resources/animations/grossini.png similarity index 100% rename from tests/cocos2d/resources/animations/grossini.png rename to tests/src/cocos2d/resources/animations/grossini.png diff --git a/tests/cocos2d/resources/animations/grossini_blue.plist b/tests/src/cocos2d/resources/animations/grossini_blue.plist similarity index 100% rename from tests/cocos2d/resources/animations/grossini_blue.plist rename to tests/src/cocos2d/resources/animations/grossini_blue.plist diff --git a/tests/cocos2d/resources/animations/grossini_blue.png b/tests/src/cocos2d/resources/animations/grossini_blue.png similarity index 100% rename from tests/cocos2d/resources/animations/grossini_blue.png rename to tests/src/cocos2d/resources/animations/grossini_blue.png diff --git a/tests/cocos2d/resources/animations/grossini_gray.plist b/tests/src/cocos2d/resources/animations/grossini_gray.plist similarity index 100% rename from tests/cocos2d/resources/animations/grossini_gray.plist rename to tests/src/cocos2d/resources/animations/grossini_gray.plist diff --git a/tests/cocos2d/resources/animations/grossini_gray.png b/tests/src/cocos2d/resources/animations/grossini_gray.png similarity index 100% rename from tests/cocos2d/resources/animations/grossini_gray.png rename to tests/src/cocos2d/resources/animations/grossini_gray.png diff --git a/tests/cocos2d/resources/b1.png b/tests/src/cocos2d/resources/b1.png similarity index 100% rename from tests/cocos2d/resources/b1.png rename to tests/src/cocos2d/resources/b1.png diff --git a/tests/cocos2d/resources/b2.png b/tests/src/cocos2d/resources/b2.png similarity index 100% rename from tests/cocos2d/resources/b2.png rename to tests/src/cocos2d/resources/b2.png diff --git a/tests/cocos2d/resources/f1.png b/tests/src/cocos2d/resources/f1.png similarity index 100% rename from tests/cocos2d/resources/f1.png rename to tests/src/cocos2d/resources/f1.png diff --git a/tests/cocos2d/resources/f2.png b/tests/src/cocos2d/resources/f2.png similarity index 100% rename from tests/cocos2d/resources/f2.png rename to tests/src/cocos2d/resources/f2.png diff --git a/tests/src/cocos2d/resources/fonts/tuffy_bold_italic-charmap.png b/tests/src/cocos2d/resources/fonts/tuffy_bold_italic-charmap.png new file mode 100644 index 0000000..0776533 Binary files /dev/null and b/tests/src/cocos2d/resources/fonts/tuffy_bold_italic-charmap.png differ diff --git a/tests/src/cocos2d/resources/grossini.png b/tests/src/cocos2d/resources/grossini.png new file mode 100644 index 0000000..afb3160 Binary files /dev/null and b/tests/src/cocos2d/resources/grossini.png differ diff --git a/tests/cocos2d/resources/grossini_dance_atlas-red.png b/tests/src/cocos2d/resources/grossini_dance_atlas-red.png similarity index 100% rename from tests/cocos2d/resources/grossini_dance_atlas-red.png rename to tests/src/cocos2d/resources/grossini_dance_atlas-red.png diff --git a/tests/cocos2d/resources/grossini_dance_atlas.png b/tests/src/cocos2d/resources/grossini_dance_atlas.png similarity index 100% rename from tests/cocos2d/resources/grossini_dance_atlas.png rename to tests/src/cocos2d/resources/grossini_dance_atlas.png diff --git a/tests/src/cocos2d/resources/grossinis_sister1.png b/tests/src/cocos2d/resources/grossinis_sister1.png new file mode 100644 index 0000000..745a5cd Binary files /dev/null and b/tests/src/cocos2d/resources/grossinis_sister1.png differ diff --git a/tests/src/cocos2d/resources/grossinis_sister2.png b/tests/src/cocos2d/resources/grossinis_sister2.png new file mode 100644 index 0000000..2fde2d4 Binary files /dev/null and b/tests/src/cocos2d/resources/grossinis_sister2.png differ diff --git a/tests/cocos2d/resources/r1.png b/tests/src/cocos2d/resources/r1.png similarity index 100% rename from tests/cocos2d/resources/r1.png rename to tests/src/cocos2d/resources/r1.png diff --git a/tests/cocos2d/resources/r2.png b/tests/src/cocos2d/resources/r2.png similarity index 100% rename from tests/cocos2d/resources/r2.png rename to tests/src/cocos2d/resources/r2.png diff --git a/tests/commonjs b/tests/src/commonjs similarity index 100% rename from tests/commonjs rename to tests/src/commonjs diff --git a/tests/commonjs.js b/tests/src/commonjs.js similarity index 85% rename from tests/commonjs.js rename to tests/src/commonjs.js index d368889..2697eba 100644 --- a/tests/commonjs.js +++ b/tests/src/commonjs.js @@ -1,15 +1,19 @@ +/*globals module exports resource require window*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + var container = document.getElementById('cocos2d-tests'); container.className = 'logs'; var logNum = 0; -window.print = function(msg, tag) { +window.print = function (msg, tag) { logNum++; var div = document.createElement('div'); div.appendChild(document.createTextNode(logNum + '. ' + msg)); div.className = 'log ' + tag; container.appendChild(div); container.scrollTop = container.offsetHeight; -} +}; while (container.firstChild) { container.removeChild(container.firstChild); diff --git a/tests/src/config.json b/tests/src/config.json new file mode 100644 index 0000000..9778971 --- /dev/null +++ b/tests/src/config.json @@ -0,0 +1,3 @@ +{ + "FLIP_Y_AXIS": true +} diff --git a/tests/src/main.js b/tests/src/main.js new file mode 100644 index 0000000..d71d3b2 --- /dev/null +++ b/tests/src/main.js @@ -0,0 +1,18 @@ +/*globals module exports resource require window*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var params = window.location.search; +if (params) { + var mod = params.split('=')[1]; + require('./' + mod).main(); +} else { + var c = document.getElementById('cocos2d-tests'); + c.style.textAlign = 'center'; + c.style.fontSize = '20pt'; + c.style.lineHeight = c.clientHeight + 'px'; + while (c.firstChild) { + c.removeChild(c.firstChild); + } + c.appendChild(document.createTextNode('Select a test to run')); +} diff --git a/tests/src/qunit.js b/tests/src/qunit.js new file mode 100644 index 0000000..5eb8116 --- /dev/null +++ b/tests/src/qunit.js @@ -0,0 +1,29 @@ +/*globals module exports resource require*/ +/*jslint undef: true, strict: true, white: true, newcap: true, browser: true, indent: 4 */ +"use strict"; + +var q = require('qunit'); + +q.test("a basic test example", function () { + q.ok(true, "this test is fine"); + var value = "hello"; + q.equals("hello", value, "We expect value to be hello"); +}); + +q.module("Module A"); + +q.test("first test within module", function () { + q.ok(true, "all pass"); +}); + +q.test("second test within module", function () { + q.ok(true, "all pass"); +}); + +q.module("Module B"); + +q.test("some other test", function () { + q.expect(2); + q.equals(true, false, "failing test"); + q.equals(true, true, "passing test"); +});