diff --git a/.gitignore b/.gitignore index 28d80ebe..454774c9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ build/api/* .*.sw? .DS_store .project -.idea \ No newline at end of file +.idea +node_modules/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..6ef04eb8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.10" +before_script: + - npm install -g grunt-cli diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 00000000..d60cb2fb --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,143 @@ +require("coffee-script"); +var fs = require('fs'); + +module.exports = function (grunt) { + var pkg = grunt.file.readJSON('package.json'); + var fileList = pkg.files, version = pkg.version; + var banner = '/**\n' + + ' * <%= pkg.name %> <%= pkg.version %>\n' + + ' * <%= pkg.author.url %>\n *\n' + + ' * Copyright <%= grunt.template.today("yyyy") %>, <%= pkg.author.name %>\n' + + ' * Dual licensed under the MIT or GPL licenses.\n' + + ' */\n\n'; + + var getFiles = function (){ + return fileList; + }; + + var docGen = function(){ + done = this.async(); + buildDir = "build/api/"; + grunt.file.mkdir(buildDir); + var callback = function(){ + console.log("Documentation created in " + buildDir); + done(); + }; + var md = require("./build/api-gen"); + md.document(getFiles(), buildDir, "build/template.html", version, callback); + }; + + // Project configuration. + grunt.initConfig({ + + pkg: grunt.file.readJSON('package.json'), + + usebanner: { + dist: { + options: { + position: 'top', + banner: banner + }, + files: { + src: ['crafty.js'] + } + } + }, + + browserify: { + dist: { + files: { + 'crafty.js': ['src/*.js'] + } + }, + debug: { + files: { + 'crafty.js': ['src/*.js'] + }, + options: { + debug: true + } + } + }, + + watch: { + files: ['src/*.js'], + tasks: ['build:dev'] + }, + + uglify: { + options: { + banner: banner + }, + build: { + src: 'crafty.js', + dest: 'crafty-min.js' + } + }, + + jshint: { + files: ['Gruntfile.js', 'src/**/*.js'], + options: { + globals: { + } + } + }, + + qunit: { + all: [ + 'tests/core.html', + 'tests/animation/animation.html', + 'tests/stage.html', + 'tests/events.html', + 'tests/math.html', + 'tests/isometric.html', + 'tests/loader.html', + 'tests/text.html', + 'tests/dom.html', + 'tests/tween.html', + 'tests/sound.html' + ] + }, + + jsvalidate: { + files: "crafty.js" + }, + + }); + + // Load the plugin that provides the "uglify" task. + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-qunit'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-jsvalidate'); + grunt.loadNpmTasks('grunt-browserify'); + grunt.loadNpmTasks('grunt-banner'); + + grunt.registerTask('version', 'Takes the version into src/version.js', function() { + fs.writeFileSync('src/version.js', 'module.exports = "' + version + '";'); + }); + + // Build development + grunt.registerTask('build:dev', ['browserify:debug', 'usebanner']); + + // Build release + grunt.registerTask('build:release', ['browserify:dist', 'usebanner']); + + // Building the documentation + grunt.registerTask('api', "Generate api documentation", docGen); + + // Default task. + grunt.registerTask('default', ['build:dev', 'jsvalidate']); + + // Run the test suite + grunt.registerTask('check', ['build:dev', 'jsvalidate', 'qunit', 'jshint']); + + // Make crafty.js ready for release - minified version + grunt.registerTask('release', ['version', 'build:release', 'uglify', 'api']); + + // Run only tests + grunt.registerTask('validate', ['qunit']); + + +}; diff --git a/README.md b/README.md index b7752da9..b4e1d6ae 100644 --- a/README.md +++ b/README.md @@ -17,64 +17,67 @@ Other Goodies: ##Using Crafty -Follow this short tutorial to get started http://craftyengine.com/tutorial/bananabomber/create-a-game - A simple game of pong: +```javascript +Crafty.init(600, 300); +Crafty.background('rgb(127,127,127)'); +//Paddles +Crafty.e("Paddle, 2D, DOM, Color, Multiway") + .color('rgb(255,0,0)') + .attr({ x: 20, y: 100, w: 10, h: 100 }) + .multiway(4, { W: -90, S: 90 }); +Crafty.e("Paddle, 2D, DOM, Color, Multiway") + .color('rgb(0,255,0)') + .attr({ x: 580, y: 100, w: 10, h: 100 }) + .multiway(4, { UP_ARROW: -90, DOWN_ARROW: 90 }); +//Ball +Crafty.e("2D, DOM, Color, Collision") + .color('rgb(0,0,255)') + .attr({ x: 300, y: 150, w: 10, h: 10, + dX: Crafty.math.randomInt(2, 5), + dY: Crafty.math.randomInt(2, 5) }) + .bind('EnterFrame', function () { + //hit floor or roof + if (this.y <= 0 || this.y >= 290) + this.dY *= -1; - Crafty.init(600, 300); - Crafty.background('rgb(127,127,127)'); - - //Paddles - Crafty.e("Paddle, 2D, DOM, Color, Multiway") - .color('rgb(255,0,0)') - .attr({ x: 20, y: 100, w: 10, h: 100 }) - .multiway(4, { W: -90, S: 90 }); - Crafty.e("Paddle, 2D, DOM, Color, Multiway") - .color('rgb(0,255,0)') - .attr({ x: 580, y: 100, w: 10, h: 100 }) - .multiway(4, { UP_ARROW: -90, DOWN_ARROW: 90 }); - - //Ball - Crafty.e("2D, DOM, Color, Collision") - .color('rgb(0,0,255)') - .attr({ x: 300, y: 150, w: 10, h: 10, - dX: Crafty.math.randomInt(2, 5), - dY: Crafty.math.randomInt(2, 5) }) - .bind('EnterFrame', function () { - //hit floor or roof - if (this.y <= 0 || this.y >= 290) - this.dY *= -1; - - if (this.x > 600) { - this.x = 300; - Crafty("LeftPoints").each(function () { - this.text(++this.points + " Points") }); - } - if (this.x < 10) { - this.x = 300; - Crafty("RightPoints").each(function () { - this.text(++this.points + " Points") }); - } - - this.x += this.dX; - this.y += this.dY; - }) - .onHit('Paddle', function () { - this.dX *= -1; - }) - - //Score boards - Crafty.e("LeftPoints, DOM, 2D, Text") - .attr({ x: 20, y: 20, w: 100, h: 20, points: 0 }) - .text("0 Points"); - Crafty.e("RightPoints, DOM, 2D, Text") - .attr({ x: 515, y: 20, w: 100, h: 20, points: 0 }) - .text("0 Points"); + if (this.x > 600) { + this.x = 300; + Crafty("LeftPoints").each(function () { + this.text(++this.points + " Points") }); + } + if (this.x < 10) { + this.x = 300; + Crafty("RightPoints").each(function () { + this.text(++this.points + " Points") }); + } + + this.x += this.dX; + this.y += this.dY; + }) + .onHit('Paddle', function () { + this.dX *= -1; +}) + +//Score boards +Crafty.e("LeftPoints, DOM, 2D, Text") + .attr({ x: 20, y: 20, w: 100, h: 20, points: 0 }) + .text("0 Points"); +Crafty.e("RightPoints, DOM, 2D, Text") + .attr({ x: 515, y: 20, w: 100, h: 20, points: 0 }) + .text("0 Points"); +``` -See the game running at http://craftyengine.com/tutorial/getting-started/how-crafty-works ##Developing -If you want to fix a bug, please submit a pull request against the development branch. +If you want to fix a bug, please submit a pull request against the development branch. Some guides to help you can be found [on the wiki](https://github.com/craftyjs/Crafty/wiki) + +If you would like to make larger contributions please catch us in the [forum](https://groups.google.com/forum/?fromgroups#!forum/craftyjs) and we will help you get started. Much appreciated :-) + + +### Quick build instructions + +The easiest way to build crafty uses [gruntjs](http://gruntjs.com/), which requires [node](nodejs.org/) and [npm](https://npmjs.org/). If you have grunt, node, and npm already installed, then run `npm install` from Crafty's root directory. (This will pull down about 30MB of node packages.) From then on, just run `grunt` to build. -If you would like to make larger contributions please catch us in the forum and we will help you get started. Much appreciated :-) \ No newline at end of file +([Full instructions here](https://github.com/craftyjs/Crafty/wiki/Building).) diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..a714aed5 --- /dev/null +++ b/bower.json @@ -0,0 +1,9 @@ +{ + "name": "crafty", + "main": "crafty.js", + "version": "0.6", + "repository": { + "type": "git", + "url": "git://github.com/craftyjs/Crafty.git" + } +} diff --git a/build/api-gen.coffee b/build/api-gen.coffee new file mode 100644 index 00000000..566a2a39 --- /dev/null +++ b/build/api-gen.coffee @@ -0,0 +1,275 @@ +# Import markdown parser +marked = require("marked"); +marked.setOptions({breaks:false, sanitize:false}) +#Import file system +fs = require 'fs' + + +docCallback = null +pendingOperations = 0 +dirOut = 'markdown/' +templateName = "doc_template.html" +data = [] +versionString = "0.0.X" + +writeOut = (name, html)-> + fs.writeFile(dirOut + cleanName(name) + '.html', html, (err) -> + console.error err if err + tracker(); + ) + +# Data structure that holds a ToC like structure +Table = { + cats: [], + comps: [], + blocks: [], +} + + +# Adds a block to the index +processBlock = (block)-> + Table.blocks[block.name] = block; + # Having a category tag means it's a component + if block.categories.length>0 + for c in block.categories + if not Table.cats[c]? + Table.cats[c] = []; + Table.cats[c].push( block ) + if not Table.comps[block.comp] + Table.comps[block.name] = {name:block.name, parts:[]} + Table.comps[block.name].block = block + + # Having a component tag means it's part of a component page + if block.comp + if not Table.comps[block.comp] + Table.comps[block.comp] = {name:block.comp, parts:[]} + Table.comps[block.comp].parts.push(block) + +class DocBlock + constructor: () -> + @content = [] + @categories = [] + @comp = null + @see = [] + @triggers = [] + @name = "" + @code = [] + @prevTag = null + + processLine: (line) => + clean = line.trim().replace(/\/\*\*\@|\*\/|\*/, '') + clean = clean.substr(1) if clean[0] is ' ' + tagged = clean.match(/\@([^\s]*)\s?(.*)/) + + if tagged? + tag = tagged[1] + value = tagged[2]?.trim() + @processTag(tag, value) + else if /^\s*\#[^\#]/.test(clean) + @name = clean[clean.indexOf('#')+1..].trim() + else + if @isFunctionTag(@prevTag) + @code.push("") + @prevTag = null + @code.push(clean) + + processTag: (tag, value) => + if @isFunctionTag(@prevTag) and not @isFunctionTag(tag) + @code.push("") + switch tag + when "category" + cats = value.split(/\s*,\s*/) + for c in cats + @categories.push(c) + when "comp" + @comp = value; + when "see" + xrefs = value.split(/\s*,\s*/) + for see in xrefs + @see.push({ + name: see + link: if see.charAt(0) is "." then "##{cleanName(see)}" else "#{cleanName(see)}.html" + }) + when "trigger" + @event = value + split = value.split(/\s+-\s+/) + @triggers.push({ + event: split[0] + description: split[1] + objName: split[3] or "Data" + objProp: split[2] or null + }) + when "sign" + @code.push("`#{value}` \n") + when "param" + if not @isFunctionTag(@prevTag) + @code.push("