├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .tern-project ├── Gruntfile.js ├── README.md ├── assets ├── buildingTiles_sheet.png ├── buildingTiles_sheet.xml ├── cityTiles_sheet.png ├── cityTiles_sheet.xml ├── landscapeTiles_sheet.png ├── landscapeTiles_sheet.xml └── preloader.gif ├── bower.json ├── config.json ├── css ├── rStats.css └── styles.css ├── game ├── main.js ├── plugins │ ├── Generate.js │ ├── Roads.js │ ├── WorldManager.js │ ├── phaser-plugin-isometric.js │ └── rStats.js ├── states │ ├── boot.js │ ├── gameover.js │ ├── menu.js │ ├── play.js │ └── preload.js └── tiles.json ├── index.html ├── package.json └── templates └── _main.js.tpl /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | bower_components 4 | dist 5 | .grunt 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "libs": [ 3 | "ecma5", 4 | "ecma6", 5 | "jquery" 6 | ], 7 | "loadEagerly": [ 8 | "/game/**/*.js" 9 | ], 10 | "dontLoad": [ 11 | "/dist/*.js" 12 | ], 13 | "plugins": { 14 | "complete_strings": {}, 15 | "doc_comment": { 16 | "fullDocs": true 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on 2014-03-28 using generator-phaser-official 0.0.8-rc-2 2 | 'use strict'; 3 | var config = require('./config.json'); 4 | var _ = require('underscore'); 5 | _.str = require('underscore.string'); 6 | 7 | // Mix in non-conflict functions to Underscore namespace if you want 8 | _.mixin(_.str.exports()); 9 | 10 | var LIVERELOAD_PORT = 35729; 11 | var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}); 12 | var mountFolder = function (connect, dir) { 13 | return connect.static(require('path').resolve(dir)); 14 | }; 15 | 16 | module.exports = function (grunt) { 17 | // load all grunt tasks 18 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); 19 | 20 | grunt.initConfig({ 21 | watch: { 22 | scripts: { 23 | files: [ 24 | 'game/**/*.js', 25 | '!game/main.js' 26 | ], 27 | options: { 28 | spawn: false, 29 | livereload: LIVERELOAD_PORT 30 | }, 31 | tasks: ['build'] 32 | } 33 | }, 34 | connect: { 35 | options: { 36 | port: 9000, 37 | // change this to '0.0.0.0' to access the server from outside 38 | hostname: 'localhost' 39 | }, 40 | livereload: { 41 | options: { 42 | middleware: function (connect) { 43 | return [ 44 | lrSnippet, 45 | mountFolder(connect, 'dist') 46 | ]; 47 | } 48 | } 49 | } 50 | }, 51 | copy: { 52 | dist: { 53 | files: [ 54 | // includes files within path and its sub-directories 55 | { expand: true, src: ['assets/**'], dest: 'dist/' }, 56 | { expand: true, flatten: true, src: ['game/plugins/*.js'], dest: 'dist/js/plugins/' }, 57 | { expand: true, flatten: true, src: ['bower_components/**/build/*.js'], dest: 'dist/js/' }, 58 | { expand: true, src: ['css/**'], dest: 'dist/' }, 59 | { expand: true, src: ['index.html'], dest: 'dist/' } 60 | ] 61 | } 62 | }, 63 | browserify: { 64 | build: { 65 | src: ['game/main.js'], 66 | dest: 'dist/js/game.js' 67 | } 68 | }, 69 | 'gh-pages': { 70 | options: { 71 | base: 'dist' 72 | }, 73 | src: ['**'] 74 | } 75 | }); 76 | 77 | grunt.registerTask('build', ['buildBootstrapper', 'browserify','copy']); 78 | grunt.registerTask('serve', ['build', 'connect:livereload', 'watch']); 79 | grunt.registerTask('default', ['serve']); 80 | grunt.registerTask('dev', ['buildBootstrapper', 'browserify','copy', 'build', 'gh-pages']) 81 | grunt.registerTask('prod', ['build', 'copy']); 82 | 83 | grunt.registerTask('buildBootstrapper', 'builds the bootstrapper file correctly', function() { 84 | var stateFiles = grunt.file.expand('game/states/*.js'); 85 | var gameStates = []; 86 | var statePattern = new RegExp(/(\w+).js$/); 87 | stateFiles.forEach(function(file) { 88 | var state = file.match(statePattern)[1]; 89 | if (!!state) { 90 | gameStates.push({shortName: state, stateName: _.capitalize(state) + 'State'}); 91 | } 92 | }); 93 | config.gameStates = gameStates; 94 | console.log(config); 95 | var bootstrapper = grunt.file.read('templates/_main.js.tpl'); 96 | bootstrapper = grunt.template.process(bootstrapper,{data: config}); 97 | grunt.file.write('game/main.js', bootstrapper); 98 | }); 99 | }; 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![IsoCitySim](https://cloud.githubusercontent.com/assets/4993074/12214387/a0745866-b657-11e5-8475-204f5e48c843.jpg) 2 | 3 | # IsoCitySim 4 | A simulation of a city using isometric tiles 5 | 6 | ## Demo 7 | Be sure to check out the demo [here](http://snollygolly.github.io/IsoCitySim/). The demo shows off city/road/terrain generation, and it random each time. You can use the arrow keys to navigate around. 8 | 9 | ## How to use IsoCitySim for fun and for profit 10 | 11 | 1. Clone down the repository and navigate to it 12 | 13 | 2. `npm install` 14 | 15 | 3. `bower install` 16 | 17 | 4. `grunt` 18 | 19 | 5. Use MAMP or something similar to host the `dist` folder 20 | 21 | 6. That's it! 22 | -------------------------------------------------------------------------------- /assets/buildingTiles_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snollygolly/IsoCitySim/d230c8b44c63eff513e027ef023a05aa4526d4cb/assets/buildingTiles_sheet.png -------------------------------------------------------------------------------- /assets/buildingTiles_sheet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /assets/cityTiles_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snollygolly/IsoCitySim/d230c8b44c63eff513e027ef023a05aa4526d4cb/assets/cityTiles_sheet.png -------------------------------------------------------------------------------- /assets/cityTiles_sheet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /assets/landscapeTiles_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snollygolly/IsoCitySim/d230c8b44c63eff513e027ef023a05aa4526d4cb/assets/landscapeTiles_sheet.png -------------------------------------------------------------------------------- /assets/landscapeTiles_sheet.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /assets/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snollygolly/IsoCitySim/d230c8b44c63eff513e027ef023a05aa4526d4cb/assets/preloader.gif -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isocitysim", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "phaser-official": "2.3.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "IsoCitySim", 3 | "gameWidth": "1024", 4 | "gameHeight": "768" 5 | } 6 | -------------------------------------------------------------------------------- /css/rStats.css: -------------------------------------------------------------------------------- 1 | .rs-base{ 2 | position: absolute; 3 | z-index: 10000; 4 | padding: 10px; 5 | background-color: #222; 6 | font-size: 10px; 7 | line-height: 1.2em; 8 | width: 350px; 9 | font-family: 'Roboto Condensed', tahoma, sans-serif; 10 | left: 0; 11 | top: 0; 12 | overflow: hidden; 13 | } 14 | 15 | .rs-base h1{ 16 | margin: 0; 17 | padding: 0; 18 | font-size: 1.4em; 19 | color: #fff; 20 | margin-bottom: 5px; 21 | cursor: pointer; 22 | } 23 | 24 | .rs-base div.rs-group{ 25 | margin-bottom: 10px; 26 | } 27 | 28 | .rs-base div.rs-group.hidden{ 29 | display: none; 30 | } 31 | 32 | .rs-base div.rs-fraction{ 33 | position: relative; 34 | margin-bottom: 5px; 35 | } 36 | 37 | .rs-base div.rs-fraction p{ 38 | width: 120px; 39 | text-align: right; 40 | margin: 0; 41 | padding: 0; 42 | } 43 | 44 | .rs-base div.rs-legend{ 45 | position: absolute; 46 | line-height: 1em; 47 | } 48 | 49 | .rs-base div.rs-counter-base{ 50 | position: relative; 51 | margin: 2px 0; 52 | height: 1em; 53 | } 54 | 55 | .rs-base span.rs-counter-id{ 56 | position: absolute; 57 | left: 0; 58 | top: 0; 59 | } 60 | 61 | .rs-base div.rs-counter-value{ 62 | position: absolute; 63 | left: 90px; 64 | width: 30px; 65 | height: 1em; 66 | top: 0; 67 | text-align: right; 68 | } 69 | 70 | .rs-base canvas.rs-canvas{ 71 | position: absolute; 72 | right: 0; 73 | } 74 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #333; 3 | } 4 | 5 | #isocitysim { 6 | border: 2px solid white; 7 | width: 1024px; 8 | margin-left: auto; 9 | margin-right: auto; 10 | cursor: pointer; 11 | } -------------------------------------------------------------------------------- /game/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //global variables 4 | window.onload = function () { 5 | var game = new Phaser.Game(1024, 768, Phaser.AUTO, 'isocitysim', null, false, false); 6 | var Roads = require('./plugins/Roads'); 7 | var Generate = require('./plugins/Generate'); 8 | var WorldManager = require('./plugins/WorldManager'); 9 | game.tiles = require('./tiles.json'); 10 | game.roads = new Roads(game); 11 | game.generate = new Generate(game); 12 | game.worldManager = new WorldManager(game); 13 | 14 | // Game States 15 | game.state.add('boot', require('./states/boot')); 16 | game.state.add('gameover', require('./states/gameover')); 17 | game.state.add('menu', require('./states/menu')); 18 | game.state.add('play', require('./states/play')); 19 | game.state.add('preload', require('./states/preload')); 20 | 21 | 22 | game.state.start('preload'); 23 | }; 24 | -------------------------------------------------------------------------------- /game/plugins/Generate.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var game; 5 | 6 | function Generate(gameObj) { 7 | console.log("* Generate Init"); 8 | game = gameObj; 9 | } 10 | 11 | Generate.prototype = { 12 | //chunks start here 13 | generateChunk: function(map, tiles){ 14 | //this generates a chunk (20x20 block) according to rules we've defined 15 | //this is where it happens. 16 | var HIGHWAY_WIDTH = game.tiles.highways.straight["n"].length + game.tiles.highways.edges["n"].length; 17 | //how much land undeveloped between highway and block 18 | var HIGHWAY_EASEMENT = 2; 19 | var HIGHWAY_SINGLE_WIDTH = (HIGHWAY_WIDTH + HIGHWAY_EASEMENT) / 2; 20 | //only half of the highway width is used on each side, that equals a full one 21 | var CITY_CHUNK_SPACE = map.units - (HIGHWAY_WIDTH + HIGHWAY_EASEMENT); 22 | var CITY_START = (map.units * HIGHWAY_SINGLE_WIDTH) + HIGHWAY_SINGLE_WIDTH; 23 | //road consts 24 | var ROAD_START_OFFSET = 4; 25 | var MIN_ROAD_SPLIT = 3; 26 | var MAX_ROAD_SPLIT = 4; 27 | //building consts 28 | //density, 1 out of X building tiles will be a Y 29 | var PARK_DENSITY = 12; 30 | var WALL_DENSITY = 12; 31 | //this will get it's own section i think 32 | var heart = { 33 | z_min: 2, 34 | z_max: 6, 35 | radius: 2 36 | }; 37 | //calculate some values 38 | heart.x = this.getRandomNumber((HIGHWAY_SINGLE_WIDTH + heart.radius), (map.units - HIGHWAY_SINGLE_WIDTH) - heart.radius); 39 | heart.y = this.getRandomNumber((HIGHWAY_SINGLE_WIDTH + heart.radius), (map.units - HIGHWAY_SINGLE_WIDTH) - heart.radius); 40 | heart.x_min = heart.x - heart.radius; 41 | heart.x_max = heart.x + heart.radius; 42 | heart.y_min = heart.y - heart.radius; 43 | heart.y_max = heart.y + heart.radius; 44 | //start the looping for layers 45 | var l = 0; 46 | var rect, box; 47 | //this is hardcoded for now, may change, may not, buildings start on 2 48 | while (l < 4){ 49 | switch (l){ 50 | case 0: 51 | //grass on dirt 52 | rect = this.generateRect(map.units, map.units, 67); 53 | tiles[l] = this.mergePartial2D(map, tiles[l], rect, 0); 54 | break; 55 | case 1: 56 | //this spawns paved areas 57 | //14 because the highway takes up 3 on each edge, this will probably change 58 | rect = this.generateRect(CITY_CHUNK_SPACE, CITY_CHUNK_SPACE, 66); 59 | //starting on 63 because that's the 4,4 after highway edges 60 | tiles[l] = this.mergePartial2DSafe(map, tiles[l], rect, CITY_START); 61 | //drawing highways 62 | tiles[l] = this.generateHighway(map, tiles[l], 0, "s", ["e"], map.units); 63 | tiles[l] = this.generateHighway(map, tiles[l], (map.units - (HIGHWAY_WIDTH / 2)), "s", ["w"], map.units); 64 | tiles[l] = this.generateHighway(map, tiles[l], 0, "e", ["s"], map.units); 65 | tiles[l] = this.generateHighway(map, tiles[l], ((map.units * map.units) - (map.units * (HIGHWAY_WIDTH / 2))), "e", ["n"], map.units); 66 | //fix the highways 67 | tiles[l] = game.roads.fixHighways(map, tiles[l], "nw"); 68 | tiles[l] = game.roads.fixHighways(map, tiles[l], "ne"); 69 | tiles[l] = game.roads.fixHighways(map, tiles[l], "se"); 70 | tiles[l] = game.roads.fixHighways(map, tiles[l], "sw"); 71 | //start to spawn the roads 72 | var x = this.getRandomNumber((ROAD_START_OFFSET + 1), (ROAD_START_OFFSET + 2)); 73 | while (x < (map.units - ROAD_START_OFFSET)){ 74 | var index = this.getIndexFromCoords(map, x, HIGHWAY_EASEMENT) 75 | tiles[l] = this.generateRoad(map, tiles[l], "city_plain", index, "s", map.units - HIGHWAY_EASEMENT); 76 | //cap the highways 77 | tiles[l] = game.roads.joinRoadHighway(map, tiles[l], x, HIGHWAY_EASEMENT, "n"); 78 | tiles[l] = game.roads.joinRoadHighway(map, tiles[l], x, map.units - 1, "s"); 79 | x += this.getRandomNumber(MIN_ROAD_SPLIT, MAX_ROAD_SPLIT); 80 | } 81 | var y = this.getRandomNumber((ROAD_START_OFFSET + 1), (ROAD_START_OFFSET + 2)); 82 | while (y < (map.units - ROAD_START_OFFSET)){ 83 | var index = this.getIndexFromCoords(map, HIGHWAY_EASEMENT, y) 84 | tiles[l] = this.generateRoad(map, tiles[l], "city_plain", index, "e", map.units - HIGHWAY_EASEMENT); 85 | //cap the highways 86 | tiles[l] = game.roads.joinRoadHighway(map, tiles[l], HIGHWAY_EASEMENT, y, "w"); 87 | tiles[l] = game.roads.joinRoadHighway(map, tiles[l], map.units - 1, y, "e"); 88 | y += this.getRandomNumber(MIN_ROAD_SPLIT, MAX_ROAD_SPLIT); 89 | } 90 | //road magic! 91 | tiles[l] = game.roads.fixRoads(map, tiles[l], "city_plain"); 92 | break; 93 | case 2: 94 | //start to generate buildings 95 | var ewTiles = game.roads.getIndices(["e", "w"]); 96 | var nsTiles = game.roads.getIndices(["n", "s"]); 97 | var i = 0; 98 | var cType, index; 99 | while (i < tiles[l].length){ 100 | //randomly place features 101 | if (tiles[l-1][i] == 66 && this.getRandomNumber(1,PARK_DENSITY) == 1){ 102 | //this will be a park 103 | tiles[l-1][i] = game.tiles.parks[this.getRandomNumber(0,game.tiles.parks.length - 1)]; 104 | }else{ 105 | //we aren't drawing a park 106 | if(this.getRandomNumber(1,WALL_DENSITY) == 1){ 107 | //we are drawing a wall 108 | cType = "wall"; 109 | }else{ 110 | cType = "building" 111 | } 112 | if (tiles[l-1][i] != 66) { 113 | //find eligible directions 114 | var eligibleDirs = []; 115 | if (ewTiles.indexOf(tiles[l-1][i]) != -1 && tiles[l-1][i - map.units] == 66){eligibleDirs.push("s");} 116 | if (nsTiles.indexOf(tiles[l-1][i]) != -1 && tiles[l-1][i + 1] == 66){eligibleDirs.push("w");} 117 | if (ewTiles.indexOf(tiles[l-1][i]) != -1 && tiles[l-1][i + map.units] == 66){eligibleDirs.push("n");} 118 | if (nsTiles.indexOf(tiles[l-1][i]) != -1 && tiles[l-1][i - 1] == 66){eligibleDirs.push("e");} 119 | //check to see what to do (draw the buildings) 120 | if (eligibleDirs.indexOf("s") != -1){ 121 | //match the north side of the road 122 | index = i - map.units; 123 | if (tiles[l][index] == 0){ 124 | if (cType == "building"){ 125 | var coords = this.getCoordsFromIndex(map, index); 126 | box = game.generate.generateBuilding("s", coords, heart); 127 | tiles = game.generate.mergePartial3DSafe(map, tiles, box, l, index); 128 | }else if (cType == "wall"){ 129 | tiles[l-1][index] = game.tiles.walls.s[this.getRandomNumber(0, (game.tiles.walls.s.length - 1))]; 130 | } 131 | } 132 | } 133 | if (eligibleDirs.indexOf("e") != -1){ 134 | //match the west side of the road 135 | index = i - 1; 136 | if (tiles[l][index] == 0){ 137 | if (cType == "building"){ 138 | var coords = this.getCoordsFromIndex(map, index); 139 | box = game.generate.generateBuilding("e", coords, heart); 140 | tiles = game.generate.mergePartial3DSafe(map, tiles, box, l, index); 141 | }else if (cType == "wall"){ 142 | tiles[l-1][index] = game.tiles.walls.e[this.getRandomNumber(0, (game.tiles.walls.e.length - 1))]; 143 | } 144 | } 145 | } 146 | if (eligibleDirs.indexOf("w") != -1){ 147 | //match the east side of the road 148 | index = i + 1; 149 | if (tiles[l][index] == 0){ 150 | if (cType == "building"){ 151 | var coords = this.getCoordsFromIndex(map, index); 152 | box = game.generate.generateBuilding("w", coords, heart); 153 | tiles = game.generate.mergePartial3DSafe(map, tiles, box, l, index); 154 | }else if (cType == "wall"){ 155 | tiles[l-1][index] = game.tiles.walls.w[this.getRandomNumber(0, (game.tiles.walls.w.length - 1))]; 156 | } 157 | } 158 | } 159 | if (eligibleDirs.indexOf("n") != -1){ 160 | //match the south side of the road 161 | index = i + map.units; 162 | if (tiles[l][index] == 0){ 163 | if (cType == "building"){ 164 | var coords = this.getCoordsFromIndex(map, index); 165 | box = game.generate.generateBuilding("n", coords, heart); 166 | tiles = game.generate.mergePartial3DSafe(map, tiles, box, l, index); 167 | }else if (cType == "wall"){ 168 | tiles[l-1][index] = game.tiles.walls.n[this.getRandomNumber(0, (game.tiles.walls.n.length - 1))]; 169 | } 170 | } 171 | } 172 | } 173 | } 174 | i++; 175 | } 176 | } 177 | l++; 178 | } 179 | return tiles; 180 | }, 181 | //highways start here 182 | generateHighway: function(map, tiles, start, direction, half, length){ 183 | //generates highways from lines (2d, pass in only one array) 184 | //lines should be expressed: {start: 1, direction: s, length: 5} 185 | var highway = game.tiles.highways.straight[direction]; 186 | var edge = game.tiles.highways.edges[direction] 187 | var fullSlice = [edge[b], highway[0], highway[1], edge[b]]; 188 | var i = 0; 189 | //for border toggle 190 | var b = 0; 191 | while (i < length){ 192 | //flip flop b 193 | //b = ((b == 0) ? 1 : 0); 194 | fullSlice = [edge[b], highway[0], highway[1], edge[b]]; 195 | //the the direction matching logic stuff 196 | if (direction == "e" || direction == "w"){ 197 | //everything is same except the offset 198 | var index = ((direction == "e") ? (start + i) : (start -1) ); 199 | var c = 0; 200 | if (half.indexOf("n") != -1){ 201 | tiles[index + (map.units * c++)] = fullSlice[0]; 202 | tiles[index + (map.units * c++)] = fullSlice[1]; 203 | } 204 | if (half.indexOf("s") != -1){ 205 | tiles[index + (map.units * c++)] = fullSlice[2]; 206 | tiles[index + (map.units * c++)] = fullSlice[3]; 207 | } 208 | }else if (direction == "n" || direction == "s"){ 209 | //everything is same except the offset 210 | var index = ((direction == "s") ? (start + (map.units * i)) : (start - (map.units * i))); 211 | var c = 0; 212 | if (half.indexOf("w") != -1){ 213 | tiles[index + (c++)] = fullSlice[0]; 214 | tiles[index + (c++)] = fullSlice[1]; 215 | } 216 | if (half.indexOf("e") != -1){ 217 | tiles[index + (c++)] = fullSlice[2]; 218 | tiles[index + (c++)] = fullSlice[3]; 219 | } 220 | } 221 | i++; 222 | } 223 | return tiles; 224 | }, 225 | //roads start here 226 | generateRoad: function(map, tiles, set, start, direction, length){ 227 | //generates roads from lines (2d, pass in only one array) 228 | //lines should be expressed: {start: 1, direction: s, length: 5} 229 | if (direction == "n" || direction == "s"){ 230 | var road = game.roads.getIndex("ns".split(""), "city_plain"); 231 | }else{ 232 | var road = game.roads.getIndex("ew".split(""), "city_plain"); 233 | } 234 | tiles[start] = road; 235 | 236 | var i = 1; 237 | while (i < length){ 238 | switch (direction) { 239 | case "n": 240 | tiles[start - (map.units * i)] = road; 241 | break; 242 | case "e": 243 | tiles[start + i] = road; 244 | break; 245 | case "w": 246 | tiles[start - i] = road; 247 | break; 248 | case "s": 249 | tiles[start + (map.units * i)] = road; 250 | break; 251 | } 252 | i++; 253 | } 254 | return tiles; 255 | }, 256 | //buildings starts here 257 | generateBuilding: function(direction, coords, heart){ 258 | //test stuff with auto types and height 259 | var type; 260 | var low = heart.z_min; 261 | var high = heart.z_max; 262 | if (coords.x >= heart.x_min && coords.x <= heart.x_max && coords.y >= heart.y_min && coords.y <= heart.y_max){ 263 | //this is going to be a commercial building 264 | type = "commercial"; 265 | //figure out the distance to the heart (int = intensity) 266 | var int_p = 1 / (heart.radius + 1); 267 | var int_m_x = Math.abs(coords.x - heart.x); 268 | var int_m_y = Math.abs(coords.y - heart.y); 269 | var int_m = (int_m_x + int_m_y) / 2; 270 | var int = 1 - (int_m * int_p); 271 | var z_mod = ((high - low) * int); 272 | high = Math.floor(z_mod + low); 273 | low = (((high - 1) < low) ? low : (high - 1)); 274 | }else{ 275 | //this is a residential building 276 | type = "residential"; 277 | low = 1; 278 | high = 2; 279 | } 280 | //end test 281 | var colors = ["red", "grey", "brown", "beige"]; 282 | var color = colors[this.getRandomNumber(0, colors.length -1)]; 283 | var building = null; 284 | //while we don't find a suitable color... 285 | while (building === null){ 286 | //try to find a suitable color 287 | if (game.tiles.buildings[type][color].bottoms[direction].length != 0){ 288 | var building = { 289 | bottom: game.tiles.buildings[type][color].bottoms[direction][this.getRandomNumber(0, game.tiles.buildings[type][color].bottoms[direction].length -1)], 290 | floors: this.getRandomNumber(low, high) 291 | }; 292 | }else{ 293 | //if we didn't find a suitable color, shuffle the colors 294 | color = colors[this.getRandomNumber(0, colors.length -1)]; 295 | } 296 | } 297 | //directional top 298 | if (direction == "n" || direction == "s"){ 299 | building.top = game.tiles.buildings[type][color].tops["ns"][this.getRandomNumber(0, game.tiles.buildings[type][color].tops["ns"].length -1)]; 300 | }else{ 301 | building.top = game.tiles.buildings[type][color].tops["ew"][this.getRandomNumber(0, game.tiles.buildings[type][color].tops["ew"].length -1)]; 302 | } 303 | //pick a roof 304 | if (this.getRandomNumber(0,1) == 1 && game.tiles.buildings[type]["all"].roofs["all"].length != 0){ 305 | //this is going to be an "all" direction roof 306 | building.roof = game.tiles.buildings[type]["all"].roofs["all"][this.getRandomNumber(0, game.tiles.buildings[type]["all"].roofs["all"].length -1)]; 307 | }else{ 308 | //directional top 309 | building.roof = game.tiles.buildings[type]["all"].roofs[direction][this.getRandomNumber(0, game.tiles.buildings[type]["all"].roofs[direction].length -1)]; 310 | } 311 | return this.makeBuilding(building); 312 | }, 313 | makeBuilding: function(building){ 314 | var returnArr = this.makeFilled3DArray(building.top, building.floors); 315 | returnArr[0][0] = building.bottom; 316 | returnArr.push([building.roof]); 317 | return returnArr; 318 | }, 319 | //terrain starts here 320 | generateMap: function(map, fill){ 321 | //generates a blank map based on dimensions 322 | var i = 0; 323 | var tiles = []; 324 | while (i < (map.units * map.units)){ 325 | tiles[i] = fill; 326 | i++; 327 | } 328 | return tiles; 329 | }, 330 | generateRect: function(width, height, fill){ 331 | var r = 0; 332 | var rows = []; 333 | while (r < height){ 334 | rows[r] = this.makeFilled2DArray(fill, width); 335 | r++; 336 | } 337 | return rows; 338 | }, 339 | generateSliceRect: function(width, height, slice){ 340 | //generates a rectangle based on the slice provided (hardcoded atm) 341 | var masterRows = []; 342 | var slices = game.tiles.slices[slice]; 343 | //row index 344 | var r = 0; 345 | while (r < slices.length){ 346 | masterRows[r] = []; 347 | masterRows[r][0] = slices[r][0]; 348 | var i = 1; 349 | while (i < (width - 1)){ 350 | masterRows[r][i] = slices[r][1]; 351 | i++; 352 | } 353 | masterRows[r][i] = slices[r][2]; 354 | r++; 355 | } 356 | //build out the final array 357 | var rectArr = []; 358 | rectArr[0] = masterRows[0]; 359 | var r = 1; 360 | while (r < (height - 1)){ 361 | rectArr[r] = masterRows[1]; 362 | r++; 363 | } 364 | rectArr[r] = masterRows[2]; 365 | return rectArr; 366 | }, 367 | //misc utility functions start here 368 | makeFilled2DArray: function(fill, length){ 369 | //makes a filled array: [0,0,0] 370 | var array = []; 371 | for (var i = 0; i < length; i++) { 372 | array[i] = fill; 373 | } 374 | return array; 375 | }, 376 | makeFilled3DArray: function(fill, length){ 377 | //makes a filled 3d array: [[0], [0]] 378 | //currently only makes single length arrays 379 | var array = []; 380 | for (var i = 0; i < length; i++) { 381 | array[i] = [fill]; 382 | } 383 | return array; 384 | }, 385 | mergePartial2D: function(map, tiles, partial, index){ 386 | //will overwrite all tiles 387 | //takes a map, and a partial map, and merges the partial into the map 388 | var i = 0; 389 | //partial should consist of an array of arrays, one array per row 390 | while (i < partial.length){ 391 | //remove items from the array 392 | tiles.splice(index + (map.units * i), partial[i].length); 393 | //remove items from the array 394 | tiles.splice.apply(tiles, [index + (map.units * i), 0].concat(partial[i])); 395 | i++; 396 | } 397 | return tiles; 398 | }, 399 | mergePartial3D: function(map, tiles, partial, layer, index){ 400 | //will overwrite all tiles 401 | //takes a map, and a partial map, and merges the partial into the map 402 | //expects 3d arrays for tiles and partial 403 | var l = 0; 404 | while (l < partial.length){ 405 | tiles[(l + layer)] = this.mergePartial2D(map, tiles[(l + layer)], partial[l], index); 406 | l++; 407 | } 408 | return tiles; 409 | }, 410 | //misc utility functions start here 411 | mergePartial2DSafe: function(map, tiles, partial, index){ 412 | //will overwrite all tiles 413 | //takes a map, and a partial map, and merges the partial into the map 414 | var i = 0; 415 | //partial should consist of an array of arrays, one array per row 416 | while (i < partial.length){ 417 | var j = 0; 418 | while (j < partial[i].length){ 419 | if (partial[i][j] != 0){ 420 | //there's some content here we want to merge 421 | tiles[index + (map.units * i) + j] = partial[i][j]; 422 | } 423 | j++; 424 | } 425 | i++; 426 | } 427 | return tiles; 428 | }, 429 | mergePartial3DSafe: function(map, tiles, partial, layer, index){ 430 | //will overwrite all tiles 431 | //takes a map, and a partial map, and merges the partial into the map 432 | //expects 3d arrays for tiles and partial 433 | var l = 0; 434 | while (l < partial.length){ 435 | tiles[(l + layer)] = this.mergePartial2DSafe(map, tiles[(l + layer)], [partial[l]], index); 436 | l++; 437 | } 438 | return tiles; 439 | }, 440 | getCoordsFromIndex: function(map, index){ 441 | //1,1 is top left corner 442 | //give it the index of the tile you want and get the x,y coords 443 | var y = Math.floor(index / map.units); 444 | var x = index - (y * map.units); 445 | return { 446 | x: x + 1, 447 | y: y + 1 448 | }; 449 | }, 450 | getIndexFromCoords: function(map, x, y){ 451 | //1,1 is top left corner 452 | //give it the x / y of the tile you want, and it'll give you its index in the array 453 | var xOffset = x - 1; 454 | var yOffset = (y - 1) * map.units; 455 | return xOffset + yOffset; 456 | }, 457 | getRandomNumber: function(min, max){ 458 | return Math.floor(Math.random() * (max - min + 1)) + min; 459 | } 460 | }; 461 | 462 | module.exports = Generate; 463 | -------------------------------------------------------------------------------- /game/plugins/Roads.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var game; 5 | 6 | function Roads(gameObj) { 7 | console.log("* Roads Init"); 8 | game = gameObj; 9 | } 10 | 11 | Roads.prototype = { 12 | fixRoads: function(map, tiles, set){ 13 | //give it all your tiles and it makes your roads perfect 14 | //Road Magic! 15 | var problemTiles = []; 16 | var nsProbs = this.findNSProblems(map, tiles); 17 | var ewProbs = this.findEWProblems(map, tiles); 18 | problemTiles = this.arrayUnique(nsProbs.concat(ewProbs)); 19 | //tiles = this.displayProblemTiles(tiles, problemTiles); 20 | //return tiles; 21 | tiles = this.fixProblemTiles(map, tiles, set, problemTiles); 22 | return tiles; 23 | }, 24 | fixHighways: function(map, tiles, corner){ 25 | //give it the tiles, the corner this join happens in, puts some corners on your highway 26 | //i wish this was more magical, like road magic. *sigh*. 27 | switch (corner){ 28 | case "nw": 29 | var cornerX = 2; 30 | var cornerY = 2; 31 | //fix the corner roads 32 | tiles[game.generate.getIndexFromCoords(map, cornerX - 1, cornerY - 1)] = game.tiles.highways.open; 33 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY - 1)] = game.tiles.highways.straight.w[1]; 34 | tiles[game.generate.getIndexFromCoords(map, cornerX - 1, cornerY)] = game.tiles.highways.straight.n[1]; 35 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY)] = game.tiles.highways.corner; 36 | //fix edge caps 37 | tiles[game.generate.getIndexFromCoords(map, cornerX + 1, cornerY)] = game.tiles.highways.edge_caps.w; 38 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY + 1)] = game.tiles.highways.edge_caps.n; 39 | break; 40 | case "ne": 41 | var cornerX = map.units - 1; 42 | var cornerY = 2; 43 | //fix the corner roads 44 | tiles[game.generate.getIndexFromCoords(map, cornerX + 1, cornerY - 1)] = game.tiles.highways.open; 45 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY - 1)] = game.tiles.highways.straight.w[1]; 46 | tiles[game.generate.getIndexFromCoords(map, cornerX + 1, cornerY)] = game.tiles.highways.straight.s[0]; 47 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY)] = game.tiles.highways.corner; 48 | //fix edge caps 49 | tiles[game.generate.getIndexFromCoords(map, cornerX - 1, cornerY)] = game.tiles.highways.edge_caps.e; 50 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY + 1)] = game.tiles.highways.edge_caps.n; 51 | break; 52 | case "se": 53 | var cornerX = map.units - 1; 54 | var cornerY = map.units - 1; 55 | //fix the corner roads 56 | tiles[game.generate.getIndexFromCoords(map, cornerX + 1, cornerY + 1)] = game.tiles.highways.open; 57 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY + 1)] = game.tiles.highways.straight.e[0]; 58 | tiles[game.generate.getIndexFromCoords(map, cornerX + 1, cornerY)] = game.tiles.highways.straight.n[0]; 59 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY)] = game.tiles.highways.corner; 60 | //fix edge caps 61 | tiles[game.generate.getIndexFromCoords(map, cornerX - 1, cornerY)] = game.tiles.highways.edge_caps.e; 62 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY - 1)] = game.tiles.highways.edge_caps.s; 63 | break; 64 | case "sw": 65 | var cornerX = 2; 66 | var cornerY = map.units - 1; 67 | //fix the corner roads 68 | tiles[game.generate.getIndexFromCoords(map, cornerX - 1, cornerY + 1)] = game.tiles.highways.open; 69 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY + 1)] = game.tiles.highways.straight.w[0]; 70 | tiles[game.generate.getIndexFromCoords(map, cornerX - 1, cornerY)] = game.tiles.highways.straight.s[1]; 71 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY)] = game.tiles.highways.corner; 72 | //fix edge caps 73 | tiles[game.generate.getIndexFromCoords(map, cornerX + 1, cornerY)] = game.tiles.highways.edge_caps.w; 74 | tiles[game.generate.getIndexFromCoords(map, cornerX, cornerY - 1)] = game.tiles.highways.edge_caps.s; 75 | break; 76 | } 77 | return tiles; 78 | }, 79 | joinRoadHighway: function(map, tiles, x, y, direction){ 80 | //joins together highways and roads 81 | switch (direction){ 82 | case "n": 83 | //set join piece 84 | tiles[game.generate.getIndexFromCoords(map, x, y - 1)] = game.tiles.highways.joins.s; 85 | //caps 86 | tiles[game.generate.getIndexFromCoords(map, x - 1, y)] = game.tiles.highways.edge_caps.e; 87 | tiles[game.generate.getIndexFromCoords(map, x + 1, y)] = game.tiles.highways.edge_caps.w; 88 | break; 89 | case "e": 90 | //set join piece 91 | tiles[game.generate.getIndexFromCoords(map, x + 1, y)] = game.tiles.highways.joins.w; 92 | //caps 93 | tiles[game.generate.getIndexFromCoords(map, x, y - 1)] = game.tiles.highways.edge_caps.s; 94 | tiles[game.generate.getIndexFromCoords(map, x, y + 1)] = game.tiles.highways.edge_caps.n; 95 | break; 96 | case "w": 97 | //set join piece 98 | tiles[game.generate.getIndexFromCoords(map, x - 1, y)] = game.tiles.highways.joins.e; 99 | //caps 100 | tiles[game.generate.getIndexFromCoords(map, x, y + 1)] = game.tiles.highways.edge_caps.n; 101 | tiles[game.generate.getIndexFromCoords(map, x, y - 1)] = game.tiles.highways.edge_caps.s; 102 | break; 103 | case "s": 104 | //set join piece 105 | tiles[game.generate.getIndexFromCoords(map, x, y + 1)] = game.tiles.highways.joins.n; 106 | //caps 107 | tiles[game.generate.getIndexFromCoords(map, x - 1, y)] = game.tiles.highways.edge_caps.e; 108 | tiles[game.generate.getIndexFromCoords(map, x + 1, y)] = game.tiles.highways.edge_caps.w; 109 | break; 110 | } 111 | return tiles; 112 | }, 113 | displayProblemTiles: function(tiles, problems){ 114 | var i = 0; 115 | while (i < problems.length){ 116 | tiles[problems[i]] = 43; 117 | i++; 118 | } 119 | return tiles; 120 | }, 121 | fixProblemTiles: function(map, tiles, set, problems){ 122 | //pass it map, tiles, and an array of problem tiles and it fixes them 123 | var i = 0; 124 | //let's work on our tiles one by one 125 | while (i < problems.length){ 126 | //this is our desired object 127 | var needle = { 128 | n: false, 129 | e: false, 130 | w: false, 131 | s: false, 132 | set: set 133 | }; 134 | //check to see if there's a road tile to the north 135 | var n = (problems[i] - map.units); 136 | if (tiles[n] != 0){ 137 | var nX = this.getDirections(tiles[n]); 138 | if (nX){ 139 | if (nX.s == true && nX.set == set){ 140 | //this tile to the north needs a south connection (us) 141 | needle.n = true; 142 | } 143 | } 144 | } 145 | //check to see if there's a road tile to the south 146 | var s = (problems[i] + map.units); 147 | if (tiles[s] != 0){ 148 | var sX = this.getDirections(tiles[s]); 149 | if (sX){ 150 | if (sX.n == true && sX.set == set){ 151 | //this tile to the south needs a north connection (us) 152 | needle.s = true; 153 | } 154 | } 155 | } 156 | //check to see if there's a road tile to the east 157 | var e = (problems[i] + 1); 158 | if (tiles[e] != 0){ 159 | var eX = this.getDirections(tiles[e]); 160 | if (eX){ 161 | if (eX.w == true && eX.set == set){ 162 | //this tile to the east needs a west connection (us) 163 | needle.e = true; 164 | } 165 | } 166 | } 167 | //check to see if there's a road tile to the west 168 | var w = (problems[i] - 1); 169 | if (tiles[w] != 0){ 170 | var wX = this.getDirections(tiles[w]); 171 | if (wX){ 172 | if (wX.e == true && wX.set == set){ 173 | //this tile to the west needs an east connection (us) 174 | needle.w = true; 175 | } 176 | } 177 | 178 | } 179 | //we have our needle now, let's find it! 180 | var index = this.getIndexFromObj(needle); 181 | if (index != false){ 182 | //we found a match 183 | tiles[problems[i]] = index; 184 | if (needle.n === true){tiles[n] = this.getIndex("ns", "city_intersection");} 185 | if (needle.e === true){tiles[e] = this.getIndex("ew", "city_intersection");} 186 | if (needle.w === true){tiles[w] = this.getIndex("ew", "city_intersection");} 187 | if (needle.s === true){tiles[s] = this.getIndex("ns", "city_intersection");} 188 | } 189 | i++; 190 | } 191 | return tiles; 192 | }, 193 | findNSProblems: function(map, tiles){ 194 | //finds problems using the n/s tile as the master tile 195 | var masterTiles = this.getIndices(["n", "s"]); 196 | var problemTiles = []; 197 | var i = 0; 198 | while (i < tiles.length){ 199 | if (masterTiles.indexOf(tiles[i]) != -1){ 200 | var n = i - map.units; 201 | var s = i + map.units; 202 | //there's a match, this is a "master tile, let's check its friends 203 | if (masterTiles.indexOf(tiles[n]) === -1){ 204 | //there's i don't recognize what's up there 205 | problemTiles.push(n) 206 | } 207 | if (masterTiles.indexOf(tiles[s]) === -1){ 208 | //there's i don't recognize what's down there 209 | problemTiles.push(s) 210 | } 211 | } 212 | i++; 213 | } 214 | return problemTiles; 215 | }, 216 | findEWProblems: function(map, tiles){ 217 | //finds problems using the e/w tile as the master tile 218 | var masterTiles = this.getIndices(["e", "w"]); 219 | var problemTiles = []; 220 | var i = 0; 221 | while (i < tiles.length){ 222 | if (masterTiles.indexOf(tiles[i]) != -1){ 223 | var e = i + 1; 224 | var w = i - 1; 225 | //there's a match, this is a "master tile, let's check its friends 226 | if (masterTiles.indexOf(tiles[e]) == -1){ 227 | //there's i don't recognize what's up there 228 | problemTiles.push(e) 229 | } 230 | if (masterTiles.indexOf(tiles[w]) == -1){ 231 | //there's i don't recognize what's down there 232 | problemTiles.push(w) 233 | } 234 | } 235 | i++; 236 | } 237 | return problemTiles; 238 | }, 239 | getIndex: function(directions, set){ 240 | //give it an array of directions and it will tell you which piece fits the bill 241 | var i = 0; 242 | var needle = { 243 | n: directions.indexOf("n") != -1 ? true : false, 244 | e: directions.indexOf("e") != -1 ? true : false, 245 | w: directions.indexOf("w") != -1 ? true : false, 246 | s: directions.indexOf("s") != -1 ? true : false, 247 | set: set 248 | } 249 | return this.getIndexFromObj(needle); 250 | }, 251 | getIndexFromObj: function(needle){ 252 | for (var key in game.tiles.roads) { 253 | if (game.tiles.roads.hasOwnProperty(key)) { 254 | if (this.compareJSON(game.tiles.roads[key], needle)){ 255 | return parseInt(key); 256 | } 257 | } 258 | } 259 | console.log("! No match found for getIndexFromObj in Roads"); 260 | //console.log(JSON.stringify(needle)); 261 | return false; 262 | }, 263 | getIndices: function(directions){ 264 | //give it an array of directions and it will tell you which pieces fits the bill (no set required) 265 | var needles = []; 266 | var needle = { 267 | n: directions.indexOf("n") != -1 ? true : false, 268 | e: directions.indexOf("e") != -1 ? true : false, 269 | w: directions.indexOf("w") != -1 ? true : false, 270 | s: directions.indexOf("s") != -1 ? true : false 271 | } 272 | for (var key in game.tiles.roads) { 273 | if (game.tiles.roads[key].n == needle.n && game.tiles.roads[key].s == needle.s){ 274 | if (game.tiles.roads[key].e == needle.e && game.tiles.roads[key].w == needle.w){ 275 | //this piece is the piece we want 276 | needles.push(parseInt(key)); 277 | } 278 | } 279 | } 280 | return needles; 281 | }, 282 | getDirections: function(index){ 283 | //give it an index and it will return a direction object back to you 284 | return game.tiles.roads[index]; 285 | }, 286 | isRoad: function(index){ 287 | 288 | }, 289 | compareJSON: function(a, b){ 290 | if (JSON.stringify(a) === JSON.stringify(b)){ 291 | return true; 292 | }else{ 293 | return false; 294 | } 295 | }, 296 | arrayUnique: function(array) { 297 | var a = array.concat(); 298 | for(var i=0; i _max ) _max = _current; 112 | _ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height ); 113 | if( alarm ) { 114 | _ctx.drawImage( _alarmCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight ); 115 | } else { 116 | _ctx.drawImage( _dotCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight ); 117 | } 118 | } 119 | 120 | _init(); 121 | 122 | return { 123 | draw: _draw 124 | } 125 | 126 | } 127 | 128 | function StackGraph( _dom, _num ) { 129 | 130 | var _canvas = document.createElement( 'canvas' ), 131 | _ctx = _canvas.getContext( '2d' ), 132 | _max = 0, 133 | _current = 0; 134 | 135 | function _init() { 136 | 137 | _canvas.width = _elWidth; 138 | _canvas.height = _elHeight * _num; 139 | _canvas.style.width = _canvas.width + 'px'; 140 | _canvas.style.height = _canvas.height + 'px'; 141 | _canvas.className = 'rs-canvas'; 142 | _dom.appendChild( _canvas ); 143 | 144 | _ctx.fillStyle = '#444444'; 145 | _ctx.fillRect( 0, 0, _canvas.width, _canvas.height ); 146 | 147 | } 148 | 149 | function _draw( v ) { 150 | _ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height ); 151 | var th = 0; 152 | iterateKeys( v, function( j ) { 153 | var h = v[ j ] * _canvas.height; 154 | _ctx.fillStyle = _colours[ j ]; 155 | _ctx.fillRect( _canvas.width - 1, th, 1, h ); 156 | th += h; 157 | } ); 158 | } 159 | 160 | _init(); 161 | 162 | return { 163 | draw: _draw 164 | } 165 | 166 | } 167 | 168 | function PerfCounter( id, group ) { 169 | 170 | var _id = id, 171 | _time, 172 | _value = 0, 173 | _total = 0, 174 | _averageValue = 0, 175 | _accumValue = 0, 176 | _accumStart = Date.now(), 177 | _accumSamples = 0, 178 | _dom = document.createElement( 'div' ), 179 | _spanId = document.createElement( 'span' ), 180 | _spanValue = document.createElement( 'div' ), 181 | _spanValueText = document.createTextNode( '' ), 182 | _def = _settings?_settings.values[ _id.toLowerCase() ]:null, 183 | _graph = new Graph( _dom, _id, _def ); 184 | 185 | _dom.className = 'rs-counter-base'; 186 | 187 | _spanId.className = 'rs-counter-id' 188 | _spanId.textContent = ( _def && _def.caption )?_def.caption:_id; 189 | 190 | _spanValue.className = 'rs-counter-value'; 191 | _spanValue.appendChild( _spanValueText ); 192 | 193 | _dom.appendChild( _spanId ); 194 | _dom.appendChild( _spanValue ); 195 | if( group ) group.div.appendChild( _dom ); 196 | else _div.appendChild( _dom ); 197 | 198 | _time = performance.now(); 199 | 200 | function _average( v ) { 201 | if( _def && _def.average ) { 202 | _accumValue += v; 203 | _accumSamples++; 204 | var t = Date.now(); 205 | if( t - _accumStart >= ( _def.avgMs || 1000 ) ) { 206 | _averageValue = _accumValue / _accumSamples; 207 | _accumValue = 0; 208 | _accumStart = t; 209 | _accumSamples = 0; 210 | } 211 | } 212 | } 213 | 214 | function _start(){ 215 | _time = performance.now(); 216 | } 217 | 218 | function _end() { 219 | _value = performance.now() - _time; 220 | _average( _value ); 221 | } 222 | 223 | function _tick() { 224 | _end(); 225 | _start(); 226 | } 227 | 228 | function _draw() { 229 | var v = ( _def && _def.average )?_averageValue:_value 230 | _spanValueText.nodeValue = Math.round( v * 100 ) / 100; 231 | var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) ); 232 | _graph.draw( _value, a ); 233 | _dom.style.color = a?'#b70000':'#ffffff'; 234 | } 235 | 236 | function _frame() { 237 | var t = performance.now(); 238 | var e = t - _time; 239 | _total++; 240 | if( e > 1000 ) { 241 | if( _def.interpolate === false ) { 242 | _value = _total; 243 | } else { 244 | _value = _total * 1000 / e; 245 | } 246 | _total = 0; 247 | _time = t; 248 | _average( _value ); 249 | } 250 | } 251 | 252 | function _set( v ) { 253 | _value = v; 254 | _average( _value ); 255 | } 256 | 257 | return { 258 | set: _set, 259 | start: _start, 260 | tick: _tick, 261 | end: _end, 262 | frame: _frame, 263 | value: function(){ return _value; }, 264 | draw: _draw 265 | } 266 | 267 | } 268 | 269 | function sample() { 270 | 271 | var _value = 0; 272 | 273 | function _set( v ) { 274 | _value = v; 275 | } 276 | 277 | return { 278 | set: _set, 279 | value: function(){ return _value; } 280 | } 281 | 282 | } 283 | 284 | var _base, 285 | _div, 286 | _height = null, 287 | _elHeight = 10, 288 | _elWidth = 200; 289 | 290 | var _perfCounters = {}, 291 | _samples = {}; 292 | 293 | function _perf( id ) { 294 | 295 | id = id.toLowerCase(); 296 | if( id === undefined ) id = 'default'; 297 | if( _perfCounters[ id ] ) return _perfCounters[ id ]; 298 | 299 | var group = null; 300 | if( _settings && _settings.groups ) { 301 | iterateKeys( _settings.groups, function( j ) { 302 | var g = _settings.groups[ parseInt( j, 10 ) ]; 303 | if( !group && g.values.indexOf( id.toLowerCase() ) != -1 ) { 304 | group = g; 305 | } 306 | } ); 307 | } 308 | 309 | var p = new PerfCounter( id, group ); 310 | _perfCounters[ id ] = p; 311 | return p; 312 | 313 | } 314 | 315 | function _init() { 316 | 317 | if( _settings.plugins ) { 318 | if( !_settings.values ) _settings.values = {}; 319 | if( !_settings.groups ) _settings.groups = []; 320 | if( !_settings.fractions ) _settings.fractions = []; 321 | for( var j = 0; j < _settings.plugins.length; j++ ) { 322 | _settings.plugins[ j ].attach( _perf ); 323 | iterateKeys( _settings.plugins[ j ].values, function( k ) { 324 | _settings.values[ k ] = _settings.plugins[ j ].values[ k ]; 325 | } ); 326 | _settings.groups = _settings.groups.concat( _settings.plugins[ j ].groups ); 327 | _settings.fractions = _settings.fractions.concat( _settings.plugins[ j ].fractions ); 328 | } 329 | } else { 330 | _settings.plugins = {}; 331 | } 332 | 333 | _base = document.createElement( 'div' ); 334 | _base.className = 'rs-base'; 335 | _div = document.createElement( 'div' ); 336 | _div.className = 'rs-container'; 337 | _div.style.height = 'auto'; 338 | _base.appendChild( _div ); 339 | document.body.appendChild( _base ); 340 | 341 | var style = window.getComputedStyle( _base, null ).getPropertyValue( 'font-size' ); 342 | //_elHeight = parseFloat( style ); 343 | 344 | if( !_settings ) return; 345 | 346 | if( _settings.groups ) { 347 | iterateKeys( _settings.groups, function( j ) { 348 | var g = _settings.groups[ parseInt( j, 10 ) ]; 349 | var div = document.createElement( 'div' ); 350 | div.className = 'rs-group'; 351 | g.div = div; 352 | var h1 = document.createElement( 'h1' ); 353 | h1.textContent = g.caption; 354 | h1.addEventListener( 'click', function( e ) { 355 | this.classList.toggle( 'hidden' ); 356 | e.preventDefault(); 357 | }.bind( div ) ); 358 | _div.appendChild( h1 ); 359 | _div.appendChild( div ); 360 | } ); 361 | } 362 | 363 | if( _settings.fractions ) { 364 | iterateKeys( _settings.fractions, function( j ) { 365 | var f = _settings.fractions[ parseInt( j, 10 ) ]; 366 | var div = document.createElement( 'div' ); 367 | div.className = 'rs-fraction'; 368 | var legend = document.createElement( 'div' ); 369 | legend.className = 'rs-legend'; 370 | 371 | var h = 0; 372 | iterateKeys( _settings.fractions[ j ].steps, function( k ) { 373 | var p = document.createElement( 'p' ); 374 | p.textContent = _settings.fractions[ j ].steps[ k ]; 375 | p.style.color = _colours[ h ]; 376 | legend.appendChild( p ); 377 | h++; 378 | } ); 379 | div.appendChild( legend ); 380 | div.style.height = h * _elHeight + 'px'; 381 | f.div = div; 382 | var graph = new StackGraph( div, h ); 383 | f.graph = graph; 384 | _div.appendChild( div ); 385 | } ); 386 | } 387 | 388 | } 389 | 390 | function _update() { 391 | 392 | iterateKeys( _settings.plugins, function( j ) { 393 | _settings.plugins[ j ].update(); 394 | } ); 395 | 396 | iterateKeys( _perfCounters, function( j ) { 397 | _perfCounters[ j ].draw(); 398 | } ); 399 | 400 | if( _settings && _settings.fractions ) { 401 | iterateKeys( _settings.fractions, function( j ) { 402 | var f = _settings.fractions[ parseInt( j, 10 ) ]; 403 | var v = []; 404 | var base = _perfCounters[ f.base.toLowerCase() ]; 405 | if( base ) { 406 | base = base.value(); 407 | iterateKeys( _settings.fractions[ j ].steps, function( k ) { 408 | var s = _settings.fractions[ j ].steps[ parseInt( k, 10 ) ].toLowerCase(); 409 | var val = _perfCounters[ s ]; 410 | if( val ) { 411 | v.push( val.value() / base ); 412 | } 413 | } ); 414 | } 415 | f.graph.draw( v ); 416 | } ); 417 | } 418 | 419 | /*if( _height != _div.clientHeight ) { 420 | _height = _div.clientHeight; 421 | _base.style.height = _height + 2 * _elHeight + 'px'; 422 | console.log( _base.clientHeight ); 423 | }*/ 424 | 425 | } 426 | 427 | _init(); 428 | 429 | return function( id ) { 430 | if( id ) return _perf( id ); 431 | return { 432 | element: _base, 433 | update: _update 434 | } 435 | } 436 | 437 | }; 438 | -------------------------------------------------------------------------------- /game/states/boot.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var game; 5 | var cursors; 6 | var rS; 7 | var wPx, hPx; 8 | var velocity = 5; 9 | 10 | function Boot() { 11 | rS = new rStats( { 12 | values: { 13 | fps: { caption: 'Framerate (FPS)' }, 14 | update: { caption: 'Total update time (ms)' }, 15 | render: { caption: 'Total render time (ms)' } 16 | } 17 | } ); 18 | } 19 | 20 | Boot.prototype = { 21 | preload: function() { 22 | game = this.game; 23 | //generate the world 24 | wPx = game.worldManager.world.chunks * (game.worldManager.world.units * 132); 25 | hPx = game.worldManager.world.chunks * (game.worldManager.world.units * 74); 26 | game.world.setBounds(0, 0, wPx, hPx); 27 | //generate all the layers 28 | game.worldManager.createWorld(game.generate.generateMap(game.worldManager.world, 0)); 29 | //build the chunk! 30 | var c = 0; 31 | while (c < game.worldManager.chunks.length){ 32 | var tiles = game.worldManager.getAllTiles(c); 33 | tiles = game.generate.generateChunk(game.worldManager.world, tiles); 34 | game.worldManager.setAllTiles(c, tiles); 35 | game.worldManager.cleanWorld(); 36 | c++; 37 | } 38 | 39 | //other stuff? 40 | game.time.advancedTiming = true; 41 | game.debug.renderShadow = false; 42 | game.stage.disableVisibilityChange = true; 43 | game.stage.smoothed = false; 44 | //set up plugins and game 45 | game.plugins.add(new Phaser.Plugin.Isometric(game)); 46 | game.physics.startSystem(Phaser.Plugin.Isometric.ISOARCADE); 47 | game.iso.anchor.setTo(0.5, 0.1); 48 | game.renderer.renderSession.roundPixels = true; 49 | //this does nothing, default is .50 50 | //game.iso.projectionAngle = Math.atan(100/200); 51 | }, 52 | create: function() { 53 | game.worldManager.drawWorld(); 54 | cursors = game.input.keyboard.createCursorKeys(); 55 | game.world.camera.roundPx = false; 56 | this.moveCamera((wPx / 2) - (1024 / 2), (hPx / 2) - (768 / 2)); 57 | }, 58 | update: function () { 59 | rS( 'FPS' ).frame(); 60 | rS( 'update' ).start(); 61 | //trigger the frame for anyone watching 62 | rS().update(); 63 | //this is how scaling is done, but this code is super rough 64 | //isoGroup.scale.setTo(2,2); 65 | if (cursors.right.isDown){ 66 | this.moveCamera((game.world.camera.x + velocity), game.world.camera.y); 67 | } 68 | if (cursors.left.isDown){ 69 | this.moveCamera((game.world.camera.x - velocity), game.world.camera.y); 70 | } 71 | if (cursors.down.isDown){ 72 | this.moveCamera(game.world.camera.x, (game.world.camera.y + velocity)); 73 | } 74 | if (cursors.up.isDown){ 75 | this.moveCamera(game.world.camera.x, (game.world.camera.y - velocity)); 76 | } 77 | rS( 'update' ).end(); 78 | }, 79 | render: function () { 80 | rS( 'render' ).start(); 81 | 82 | rS( 'render' ).end(); 83 | rS().update(); 84 | }, 85 | moveCamera: function(x, y){ 86 | //set the camera first 87 | game.world.camera.setPosition(x,y); 88 | //get the real world view coords of the cam 89 | var isoCam = game.world.camera.view; 90 | //make a rectangle out of them 91 | //TODO: change resolution to consts 92 | var viewport = { 93 | left: isoCam.x, 94 | right: isoCam.x + 1024, 95 | top: isoCam.y, 96 | bottom: isoCam.y + 768 97 | }; 98 | //go through each chunk, and check to see if it's in frame or not 99 | var i = 0; 100 | while (i < game.worldManager.chunks.length){ 101 | if (intersectRect(game.worldManager.chunks[i], viewport) === true){ 102 | //do something 103 | game.worldManager.chunks[i].group.visible = true; 104 | //console.log("chunk : " + i + " is visible"); 105 | }else{ 106 | game.worldManager.chunks[i].group.visible = false; 107 | //console.log("chunk : " + i + " is invisible"); 108 | } 109 | i++; 110 | } 111 | //functions 112 | function intersectRect(r1, r2) { 113 | // console.log("intersect: (chunk / camera)"); 114 | // console.log("camera.left (" + r2.left + ") > chunk.right (" + r1.right + ") - [" + ((r2.left > r1.right)?"bad":"good") + "]"); 115 | // console.log("camera.right (" + r2.right + ") > chunk.left (" + r1.left + ") - [" + ((r2.right < r1.left)?"bad":"good") + "]"); 116 | // console.log("camera.top (" + r2.top + ") > chunk.bottom (" + r1.bottom + ") - [" + ((r2.top > r1.bottom)?"bad":"good") + "]"); 117 | // console.log("camera.bottom (" + r2.bottom + ") > chunk.top (" + r1.top + ") - [" + ((r2.bottom < r1.top)?"bad":"good") + "]"); 118 | return !(r2.left > r1.right || 119 | r2.right < r1.left || 120 | r2.top > r1.bottom || 121 | r2.bottom < r1.top); 122 | } 123 | } 124 | }; 125 | 126 | module.exports = Boot; 127 | -------------------------------------------------------------------------------- /game/states/gameover.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | function GameOver() {} 4 | 5 | GameOver.prototype = { 6 | preload: function () { 7 | 8 | }, 9 | create: function () { 10 | var style = { font: '65px Arial', fill: '#ffffff', align: 'center'}; 11 | this.titleText = this.game.add.text(this.game.world.centerX,100, 'Game Over!', style); 12 | this.titleText.anchor.setTo(0.5, 0.5); 13 | 14 | this.congratsText = this.game.add.text(this.game.world.centerX, 200, 'You Win!', { font: '32px Arial', fill: '#ffffff', align: 'center'}); 15 | this.congratsText.anchor.setTo(0.5, 0.5); 16 | 17 | this.instructionText = this.game.add.text(this.game.world.centerX, 300, 'Click To Play Again', { font: '16px Arial', fill: '#ffffff', align: 'center'}); 18 | this.instructionText.anchor.setTo(0.5, 0.5); 19 | }, 20 | update: function () { 21 | if(this.game.input.activePointer.justPressed()) { 22 | this.game.state.start('play'); 23 | } 24 | } 25 | }; 26 | module.exports = GameOver; 27 | -------------------------------------------------------------------------------- /game/states/menu.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | function Menu() {} 4 | 5 | Menu.prototype = { 6 | preload: function() { 7 | 8 | }, 9 | create: function() { 10 | var style = { font: '65px Arial', fill: '#ffffff', align: 'center'}; 11 | this.sprite = this.game.add.sprite(this.game.world.centerX, 138, 'yeoman'); 12 | this.sprite.anchor.setTo(0.5, 0.5); 13 | 14 | this.titleText = this.game.add.text(this.game.world.centerX, 300, '\'Allo, \'Allo!', style); 15 | this.titleText.anchor.setTo(0.5, 0.5); 16 | 17 | this.instructionsText = this.game.add.text(this.game.world.centerX, 400, 'Click anywhere to play "Click The Yeoman Logo"', { font: '16px Arial', fill: '#ffffff', align: 'center'}); 18 | this.instructionsText.anchor.setTo(0.5, 0.5); 19 | 20 | this.sprite.angle = -20; 21 | this.game.add.tween(this.sprite).to({angle: 20}, 1000, Phaser.Easing.Linear.NONE, true, 0, 1000, true); 22 | }, 23 | update: function() { 24 | if(this.game.input.activePointer.justPressed()) { 25 | this.game.state.start('play'); 26 | } 27 | } 28 | }; 29 | 30 | module.exports = Menu; 31 | -------------------------------------------------------------------------------- /game/states/play.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | function Play() {} 4 | Play.prototype = { 5 | create: function() { 6 | 7 | }, 8 | update: function() { 9 | 10 | } 11 | }; 12 | 13 | module.exports = Play; 14 | -------------------------------------------------------------------------------- /game/states/preload.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | function Preload() { 4 | this.asset = null; 5 | this.ready = false; 6 | } 7 | 8 | Preload.prototype = { 9 | preload: function() { 10 | console.log("* Preload Init"); 11 | this.asset = this.add.sprite(this.width/2,this.height/2, 'preloader'); 12 | this.asset.anchor.setTo(0.5, 0.5); 13 | 14 | this.load.onLoadComplete.addOnce(this.onLoadComplete, this); 15 | this.load.setPreloadSprite(this.asset); 16 | this.load.atlasXML('landscape', 'assets/landscapeTiles_sheet.png', 'assets/landscapeTiles_sheet.xml'); 17 | this.load.atlasXML('building', 'assets/buildingTiles_sheet.png', 'assets/buildingTiles_sheet.xml'); 18 | this.load.atlasXML('city', 'assets/cityTiles_sheet.png', 'assets/cityTiles_sheet.xml'); 19 | 20 | }, 21 | create: function() { 22 | this.asset.cropEnabled = false; 23 | }, 24 | update: function() { 25 | if(!!this.ready) { 26 | this.game.state.start('boot'); 27 | }else{ 28 | } 29 | }, 30 | onLoadComplete: function() { 31 | this.ready = true; 32 | } 33 | }; 34 | 35 | module.exports = Preload; 36 | -------------------------------------------------------------------------------- /game/tiles.json: -------------------------------------------------------------------------------- 1 | { 2 | "slices": { 3 | "island":[ 4 | [53,42,61], 5 | [35,59,34], 6 | [60,27,68] 7 | ], 8 | "hill":[ 9 | [0,10,0], 10 | [16,67,15], 11 | [0,22,0] 12 | ], 13 | "paved":[ 14 | [114,80,119], 15 | [87,81,88], 16 | [118,95,122] 17 | ], 18 | "grass_road":[ 19 | [123,74,126], 20 | [82,0,82], 21 | [125,74,127] 22 | ], 23 | "city_road":[ 24 | [122,73,125], 25 | [81,0,81], 26 | [124,73,126] 27 | ] 28 | }, 29 | "highways": { 30 | "open": 80, 31 | "corner": 59, 32 | "edges": { 33 | "n": [75,54], 34 | "e": [83,62], 35 | "w": [83,62], 36 | "s": [75,54] 37 | }, 38 | "edge_caps":{ 39 | "n": 61, 40 | "e": 69, 41 | "w": 68, 42 | "s": 76 43 | }, 44 | "joins": { 45 | "n": 93, 46 | "e": 101, 47 | "w": 100, 48 | "s": 107 49 | }, 50 | "straight": { 51 | "n": [86,87], 52 | "e": [79,94], 53 | "w": [79,94], 54 | "s": [86,87] 55 | } 56 | }, 57 | "roads": { 58 | "89": { 59 | "n": true, 60 | "e": true, 61 | "w": true, 62 | "s": true, 63 | "set": "city_plain" 64 | }, 65 | "96": { 66 | "n": false, 67 | "e": true, 68 | "w": true, 69 | "s": true, 70 | "set": "city_plain" 71 | }, 72 | "88": { 73 | "n": true, 74 | "e": false, 75 | "w": true, 76 | "s": true, 77 | "set": "city_plain" 78 | }, 79 | "103": { 80 | "n": true, 81 | "e": true, 82 | "w": true, 83 | "s": false, 84 | "set": "city_plain" 85 | }, 86 | "95": { 87 | "n": true, 88 | "e": true, 89 | "w": false, 90 | "s": true, 91 | "set": "city_plain" 92 | }, 93 | "122":{ 94 | "n": false, 95 | "e": true, 96 | "w": false, 97 | "s": true, 98 | "set": "city_plain" 99 | }, 100 | "125":{ 101 | "n": false, 102 | "e": false, 103 | "w": true, 104 | "s": true, 105 | "set": "city_plain" 106 | }, 107 | "124":{ 108 | "n": true, 109 | "e": true, 110 | "w": false, 111 | "s": false, 112 | "set": "city_plain" 113 | }, 114 | "126":{ 115 | "n": true, 116 | "e": false, 117 | "w": true, 118 | "s": false, 119 | "set": "city_plain" 120 | }, 121 | "73":{ 122 | "n": false, 123 | "e": true, 124 | "w": true, 125 | "s": false, 126 | "set": "city_plain" 127 | }, 128 | "81":{ 129 | "n": true, 130 | "e": false, 131 | "w": false, 132 | "s": true, 133 | "set": "city_plain" 134 | }, 135 | "56":{ 136 | "n": true, 137 | "e": false, 138 | "w": false, 139 | "s": true, 140 | "set": "city_intersection" 141 | }, 142 | "64":{ 143 | "n": false, 144 | "e": true, 145 | "w": true, 146 | "s": false, 147 | "set": "city_intersection" 148 | } 149 | }, 150 | "parks":[43,51,59,67], 151 | "walls":{ 152 | "n": [12,23], 153 | "e": [8,17], 154 | "s": [7,16], 155 | "w": [4,11], 156 | }, 157 | "buildings": { 158 | "residential":{ 159 | "red":{ 160 | "bottoms": { 161 | "n": [92], 162 | "e": [36], 163 | "s": [30], 164 | "w": [106], 165 | }, 166 | "tops": { 167 | "ns": [45,52], 168 | "ew": [49,54] 169 | } 170 | }, 171 | "grey":{ 172 | "bottoms": { 173 | "n": [85], 174 | "e": [42], 175 | "s": [37], 176 | "w": [85], 177 | }, 178 | "tops": { 179 | "ns": [50,55], 180 | "ew": [53,56] 181 | } 182 | }, 183 | "brown":{ 184 | "bottoms": { 185 | "n": [131], 186 | "e": [21], 187 | "s": [14], 188 | "w": [131], 189 | }, 190 | "tops": { 191 | "ns": [32,43], 192 | "ew": [38,47] 193 | } 194 | }, 195 | "beige":{ 196 | "bottoms": { 197 | "n": [130], 198 | "e": [29], 199 | "s": [22], 200 | "w": [130], 201 | }, 202 | "tops": { 203 | "ns": [39,48], 204 | "ew": [44,51] 205 | } 206 | }, 207 | "all":{ 208 | "roofs": { 209 | "n": [59,64,66,73,75,77,89,91,105], 210 | "e": [61,68,70,80,82,84,96,112], 211 | "s": [58,63,65,72,74,76,88,90,104], 212 | "w": [57,60,62,67,69,71,81,83,97,98], 213 | "all": [] 214 | } 215 | } 216 | }, 217 | "commercial":{ 218 | "red":{ 219 | "bottoms": { 220 | "n": [33,46,92], 221 | "e": [1,9,17,26,41,99], 222 | "s": [2,10,18,34,113,123], 223 | "w": [25,40,106], 224 | }, 225 | "tops": { 226 | "ns": [16,23], 227 | "ew": [16,23] 228 | } 229 | }, 230 | "grey":{ 231 | "bottoms": { 232 | "n": [19,35,85,114], 233 | "e": [3,12,28,93,100,107,116,124], 234 | "s": [4,20,101,108,109,115,117,125], 235 | "w": [11,27,122], 236 | }, 237 | "tops": { 238 | "ns": [24,31], 239 | "ew": [24,31] 240 | } 241 | }, 242 | "brown":{ 243 | "bottoms": { 244 | "n": [131], 245 | "e": [], 246 | "s": [], 247 | "w": [131], 248 | }, 249 | "tops": { 250 | "ns": [7,129], 251 | "ew": [7,129] 252 | } 253 | }, 254 | "beige":{ 255 | "bottoms": { 256 | "n": [130], 257 | "e": [], 258 | "s": [], 259 | "w": [130], 260 | }, 261 | "tops": { 262 | "ns": [8,15], 263 | "ew": [8,15] 264 | } 265 | }, 266 | "all":{ 267 | "roofs": { 268 | "n": [87,103], 269 | "e": [94,110], 270 | "s": [86,102], 271 | "w": [79,95], 272 | "all": [5,6,13,111,118,119,120,121,127,128] 273 | } 274 | } 275 | } 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | IsoCitySim 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isocitysim", 3 | "private": true, 4 | "devDependencies": { 5 | "bower": "~0.9.2", 6 | "browserify": "~3.38.0", 7 | "connect-livereload": "~0.1.3", 8 | "grunt": "~0.4.1", 9 | "grunt-browserify": "~1.3.0", 10 | "grunt-contrib-connect": "~0.2.0", 11 | "grunt-contrib-copy": "*", 12 | "grunt-contrib-watch": "~0.4.3", 13 | "grunt-gh-pages": "^0.10.0", 14 | "grunt-html-build": "~0.3.2", 15 | "grunt-open": "~0.2.0", 16 | "matchdep": "~0.1.2", 17 | "moment": "~2.0.0", 18 | "underscore": "*", 19 | "underscore.string": "*" 20 | }, 21 | "engines": { 22 | "node": ">=0.8.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /templates/_main.js.tpl: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //global variables 4 | window.onload = function () { 5 | var game = new Phaser.Game(<%= gameWidth %>, <%= gameHeight %>, Phaser.AUTO, '<%= _.slugify(projectName) %>', null, false, false); 6 | var Roads = require('./plugins/Roads'); 7 | var Generate = require('./plugins/Generate'); 8 | var WorldManager = require('./plugins/WorldManager'); 9 | game.tiles = require('./tiles.json'); 10 | game.roads = new Roads(game); 11 | game.generate = new Generate(game); 12 | game.worldManager = new WorldManager(game); 13 | 14 | // Game States 15 | <% _.forEach(gameStates, function(gameState) { %>game.state.add('<%= gameState.shortName %>', require('./states/<%= gameState.shortName %>')); 16 | <% }); %> 17 | 18 | game.state.start('preload'); 19 | }; 20 | --------------------------------------------------------------------------------