878 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			878 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * Michael Soukup, 2014
 | |
| */
 | |
| 
 | |
| 
 | |
| //var DIM = [window.innerWidth, window.innerHeight];
 | |
| 
 | |
| function zeros(m, n) {
 | |
|     var mat = [];
 | |
|     for (var i=0; i<m; i++) {
 | |
|         mat.push([]);
 | |
|         for (var j=0; j<n; j++) {
 | |
|             mat[i].push(0);
 | |
|         }
 | |
|     }
 | |
|     return mat
 | |
| }
 | |
| function nearestMod0(f, n) {
 | |
|     var mod = f % n;
 | |
|     if (mod < n/2) { // floor
 | |
|         return f-mod
 | |
|     }
 | |
|     else { // ceil
 | |
|         return f+n-mod
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| function Vector(x, y) {
 | |
|     this.x = x;
 | |
|     this.y = y;
 | |
| }
 | |
| Vector.prototype.add = function(v) {
 | |
|     this.x += v.x;
 | |
|     this.y += v.y;
 | |
| }
 | |
| Vector.prototype.sub = function(v) {
 | |
|     this.x -= v.x;
 | |
|     this.y -= v.y;
 | |
| }
 | |
| Vector.prototype.dot = function(v) {
 | |
|     return this.x*v.x + this.y*v.y
 | |
| }
 | |
| Vector.prototype.setLength = function(newlen) {
 | |
|     var len = this.getLength();
 | |
|     this.x = (this.x*newlen)/len;
 | |
|     this.y = (this.y*newlen)/len;
 | |
| }
 | |
| Vector.prototype.getLength = function() {
 | |
|     return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2))
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| function Frame(coords, dim) {
 | |
|     this.coords = coords;
 | |
|     this.dim = dim;
 | |
| }
 | |
| Frame.prototype.empty = function() {
 | |
|     return (this.dim.x <= 0 || this.dim.y <= 0)
 | |
| }
 | |
| Frame.prototype.move = function(u) {
 | |
|     this.coords.add(u);
 | |
| }
 | |
| Frame.prototype.align = function(mod) {
 | |
|     this.coords.x = nearestMod0(this.coords.x, mod);
 | |
|     this.coords.y = nearestMod0(this.coords.y, mod);
 | |
|     this.dim.x = nearestMod0(this.dim.x, mod);
 | |
|     this.dim.y = nearestMod0(this.dim.y, mod);
 | |
| }
 | |
| Frame.prototype.overlaps = function(f) {
 | |
|     var dx = f.coords.x - this.coords.x,
 | |
|         dy = f.coords.y - this.coords.y,
 | |
|         inter_x = ((dx > 0 && this.dim.x > dx) || (dx < 0 && f.dim.x < -dx)),
 | |
|         inter_y = ((dy > 0 && this.dim.y > dy) || (dy < 0 && f.dim.y < -dy));
 | |
| 
 | |
|     return inter_x && inter_y
 | |
| }
 | |
| Frame.prototype.join = function(f) {
 | |
|     // Expands frame to also fit f
 | |
|     var x_min = Math.min(this.coords.x, f.coords.x),
 | |
|         y_min = Math.min(this.coords.y, f.coords.y),
 | |
|         x_max = Math.max(this.coords.x+this.dim.x, f.coords.x+f.dim.x),
 | |
|         y_max = Math.max(this.coords.y+this.dim.y, f.coords.y+f.dim.y);
 | |
| 
 | |
|     this.coords.x = x_min;
 | |
|     this.coords.y = y_min;
 | |
|     this.dim.x = x_max - x_min;
 | |
|     this.dim.y = y_max - y_min;
 | |
| }
 | |
| Frame.prototype.intersect = function(f) {
 | |
|     // this AND f
 | |
|     var dx = f.coords.x - this.coords.x,
 | |
|         dy = f.coords.y - this.coords.y;
 | |
| 
 | |
|     if (dx > 0) {
 | |
|         this.coords.x = f.coords.x;
 | |
|         this.dim.x = Math.min(this.dim.x - dx, f.dim.x);
 | |
|     }
 | |
|     else {
 | |
|         this.dim.x = Math.min(f.dim.x + dx, this.dim.x);
 | |
|     }
 | |
|     if (dy > 0) {
 | |
|         this.coords.y = f.coords.y;
 | |
|         this.dim.y = Math.min(this.dim.y - dy, f.dim.y);
 | |
|     }
 | |
|     else {
 | |
|         this.dim.y = Math.min(f.dim.y + dy, this.dim.y);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| var CELL_COL = {
 | |
|         0: '#000',
 | |
|         1: '#222',
 | |
|         2: '#484',
 | |
|         3: '#a44',
 | |
|         4: '#8a8a8a'
 | |
|     },
 | |
|     CELL_T = {
 | |
|         'empty': 0,
 | |
|         'wall': 1,
 | |
|         'player': 2,
 | |
|         'enemy': 3,
 | |
|         'conway': 4
 | |
|     },
 | |
|     CELL_CONFIGS = {
 | |
|         'player0': [
 | |
|             [0,2,2,0,0,0],
 | |
|             [0,0,0,0,0,0],
 | |
|             [0,0,0,0,0,0],
 | |
|             [0,0,0,4,4,0],
 | |
|             [0,0,4,0,4,0],
 | |
|             [0,0,0,4,0,0]
 | |
|         ],
 | |
|         'enemy0': [
 | |
|             [0,3,3,3,3,0],
 | |
|             [3,4,4,0,3,3],
 | |
|             [3,4,0,0,0,3],
 | |
|             [3,0,0,4,4,3],
 | |
|             [3,0,4,0,3,3],
 | |
|             [0,3,3,3,0,0]
 | |
|         ],
 | |
|         'organism0': [
 | |
|             [0,0,0,0,0,0,4,4],
 | |
|             [0,0,4,4,4,4,4,4],
 | |
|             [0,0,0,4,0,0,0,0],
 | |
|             [0,4,0,0,0,0,0,0],
 | |
|             [0,4,4,4,0,4,0,4],
 | |
|             [4,4,4,0,4,4,4,4],
 | |
|             [0,0,4,4,4,0,0,0]
 | |
|         ],
 | |
|         'box': [
 | |
|             [0,0,0,0],
 | |
|             [0,4,4,0],
 | |
|             [0,4,4,0],
 | |
|             [0,0,0,0]
 | |
|         ],
 | |
|         'diamond': [
 | |
|             [0,4,0,0],
 | |
|             [4,0,4,0],
 | |
|             [0,4,0,0],
 | |
|             [0,0,0,0]
 | |
|         ]
 | |
|     };
 | |
| 
 | |
| 
 | |
| function Ndist(N, r) {
 | |
|     var dist = [0,0,0,0,0];
 | |
|     for (var x=0; x<N.length; x++) {
 | |
|         for (var y=0; y<N.length; y++) {
 | |
|             if (x != r && y != r) {
 | |
|                 dist[N[x][r]] += 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return dist
 | |
| }
 | |
| function cell_0_update(N, r) {
 | |
|     // count neighbours for now
 | |
|     var dist = Ndist(N, r);
 | |
|     if (dist[4] == 3) {
 | |
|         return 4
 | |
|     }
 | |
|     else  {
 | |
|         return 0
 | |
|     }
 | |
| }
 | |
| function cell_1_update(N, r) {
 | |
|     return 1
 | |
| }
 | |
| function cell_2_update(N, r) {
 | |
|     // player cell
 | |
|     return 2
 | |
| }
 | |
| function cell_3_update(N, r) {
 | |
|     // enemy cell
 | |
|     return 3
 | |
| }
 | |
| function cell_4_update(N, r) {
 | |
|     // conway live cells
 | |
|     var dist = Ndist(N, r);
 | |
|     if (dist[2] == 2 && dist[4] > 2) {
 | |
|         return 2
 | |
|     }
 | |
|     else if (dist[4] == 2 || dist[4] == 3) {
 | |
|         return 4
 | |
|     }
 | |
|     else {
 | |
|         return 0
 | |
|     }
 | |
| }
 | |
| function cellNext(N) {
 | |
|     // Size of neighbourhood N is nxn where n is (r*2 + 1), r in {1,2,3...}:
 | |
|     // 3x3, 5x5, 7x7, ...
 | |
| 
 | |
|     var r = (N.length - 1) / 2, // must be int
 | |
|         cell = N[r][r];
 | |
| 
 | |
|     switch (cell) {
 | |
|         case 0:
 | |
|             return cell_0_update(N, r);
 | |
|         case 1:
 | |
|             return cell_1_update(N, r);
 | |
|         case 2:
 | |
|             return cell_2_update(N, r);
 | |
|         case 3:
 | |
|             return cell_3_update(N, r);
 | |
|         case 4:
 | |
|             return cell_4_update(N, r);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| // Every organism has a pointer to the environment
 | |
| 
 | |
| // dim_cam, coords_cam, px_tile, dim_frame, coords_frame, tiles_frame
 | |
| 
 | |
| // function Organism(configuration, x, y, tilesize) {
 | |
| //     // Tiles can be of any size px_tile_min*n, n in N
 | |
| 
 | |
| //     this.p = new Vector(x, y); // continuous
 | |
| //     this.v = new Vector(0, 0);
 | |
| 
 | |
| //     this.px_tile = tilesize;
 | |
| //     this.tiles = new Vector(configuration[0].length, configuration.length);
 | |
| 
 | |
| //     this.config = configuration;
 | |
| //     this.config_buf = zeros(this.tiles.x, this.tiles.y);
 | |
| 
 | |
| //     this.frame = new Frame(new Vector(nearestMod0(x, tilesize), nearestMod0(y, tilesize)),
 | |
| //                            new Vector(tilesize*this.tiles.x, tilesize*this.tiles.y));
 | |
| 
 | |
| //     //this.coords_center = null // keep track of center for steering and battle
 | |
| 
 | |
| // }
 | |
| // Organism.prototype.getNeighbourhood = function(cx, cy, r) {
 | |
| //     var n = (r*2)+1,
 | |
| //         N = zeros(n,n);
 | |
| 
 | |
| //     for (var x=cx-r; x<=cx+r; x++) {
 | |
| //         for (var y=cy-r; y<=cy+r; y++) {
 | |
| //             if ((x < 0 || x >= this.tiles.x) || (y < 0 || y >= this.tiles.y)) {
 | |
| //                 N[x+r-cx][y+r-cy] = 0; // Tiles outside constraints are 0 anyways
 | |
| //             }
 | |
| //             else {
 | |
| //                 N[x+r-cx][y+r-cy] = this.config[x][y];
 | |
| //             }
 | |
| //         }
 | |
| //     }
 | |
| //     return N
 | |
| // }
 | |
| // Organism.prototype.updateCells = function() {
 | |
| //     // find player cell center
 | |
| //     for (var x=0; x<this.tiles.x; x++) {
 | |
| //         for (var y=0; y<this.tiles.y; y++) {
 | |
| //             this.config_buf[x][y] = cellNext(this.getNeighbourhood(x, y, 1));
 | |
| //             // update cell according to neighborhood
 | |
| //             // (x', y') = f(x, y)
 | |
| //         }
 | |
| //     }
 | |
| //     this.config = this.config_buf;
 | |
| // }
 | |
| // Organism.prototype.updateFrame = function() {
 | |
| 
 | |
| // }
 | |
| // Organism.prototype.playerMove = function(dF, dt) {
 | |
| //     this.v.x = dF.x/dt;
 | |
| //     this.v.y = dF.y/dt;
 | |
| 
 | |
| //     this.p.add(dF); // Move the whole box. dF controls position
 | |
| // }
 | |
| // Organism.prototype.playerUpdate = function(dF, dt) {
 | |
| //     this.frame.move(dF);
 | |
| //     this.frame.fitCoords(this.px_tile);
 | |
| //     this.updateCells();
 | |
| // }
 | |
| 
 | |
| // Organism.prototype.framesOverlap = function(o) {
 | |
| //     xoutside || youtside
 | |
| //     return (this.coords.x < o.coords.x+o.dim.x) && (this.dim.x )
 | |
| // }
 | |
| // Organism.prototype.mergeOrganism = function(o) {
 | |
| 
 | |
| // }
 | |
| 
 | |
| function Organism(configuration, x, y, tilesize) {
 | |
|     // Tiles can be of any size px_tile_min*n, n in N
 | |
| 
 | |
|     //this.pos = new Vector(x, y); // continuous
 | |
|     //this.v = new Vector(0, 0);
 | |
| 
 | |
|     this.px_tile = tilesize;
 | |
|     this.tiles = new Vector(configuration[0].length, configuration.length);
 | |
| 
 | |
|     this.frame_tilemargin = 2;
 | |
|     this.frame = new Frame(new Vector(x, y), new Vector(tilesize*this.tiles.x, tilesize*this.tiles.y));
 | |
| 
 | |
|     this.config = configuration;
 | |
| 
 | |
| 
 | |
| }
 | |
| Organism.prototype.getNeighbourhood = function(cx, cy, r) {
 | |
|     var n = (r*2)+1,
 | |
|         N = zeros(n,n);
 | |
| 
 | |
|     for (var x=cx-r; x<=cx+r; x++) {
 | |
|         for (var y=cy-r; y<=cy+r; y++) {
 | |
|             if ((x < 0 || x >= this.tiles.x) || (y < 0 || y >= this.tiles.y)) {
 | |
|                 N[x+r-cx][y+r-cy] = 0; // Tiles outside constraints are 0 anyways
 | |
|             }
 | |
|             else {
 | |
|                 N[x+r-cx][y+r-cy] = this.config[x][y];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return N
 | |
| }
 | |
| Organism.prototype.updateCells = function() {
 | |
|     var config_buf = zeros(this.tiles.x, this.tiles.y);
 | |
| 
 | |
|     for (var x=0; x<this.tiles.x; x++) {
 | |
|         for (var y=0; y<this.tiles.y; y++) {
 | |
|             this.config_buf[x][y] = cellNext(this.getNeighbourhood(x, y, 1));
 | |
|             // update cell according to neighborhood
 | |
|             // (x', y') = f(x, y)
 | |
|         }
 | |
|     }
 | |
|     this.config = config_buf;
 | |
| }
 | |
| Organism.prototype.move = function(dF, dt) {
 | |
|     if (dF.x <= 0) {
 | |
|         this.frame.coords.x += dF.x;
 | |
|     }
 | |
|     else {
 | |
|         this.frame.dim.x += dF.x;
 | |
|     }
 | |
|     if (dF.y <= 0) {
 | |
|         this.frame.coords.y += dF.y;
 | |
|     }
 | |
|     else {
 | |
|         this.frame.dim.y += dF.y;
 | |
|     }
 | |
| }
 | |
| Organism.prototype.setConfig = function(new_tiles) {
 | |
|     var diffx = new_tiles.x - this.tiles.x,
 | |
|         diffy = new_tiles.y - this.tiles.y,
 | |
|         config = zeros(new_tiles.x, new_tiles.y),
 | |
|         x_2 = Math.floor(Math.min(this.tiles.x / 2 - 1, new_tiles.x / 2 - 1)),
 | |
|         y_2 = Math.floor(Math.min(this.tiles.y / 2 - 1, new_tiles.y / 2 - 1));
 | |
| 
 | |
|     for (var x=0; x<x_2; x++) {
 | |
|         for (var y=0; y<y_2; y++) {
 | |
|             config[x][y] = this.config[x][y];
 | |
|             config[new_tiles.x-1-x][new_tiles.y-1-y] = this.config[this.tiles.x-1-x][this.tiles.y-1-y];
 | |
|         }
 | |
|     }
 | |
|     this.config = config;
 | |
|     this.tiles = new_tiles;
 | |
| }
 | |
| Organism.prototype.step = function(dF, dt) {
 | |
| 
 | |
|     var x = this.frame.dim.x + this.K_p*(this.a_ref - this.frame.dim.x),
 | |
|         y = this.frame.dim.y + this.K_p*(this.a_ref - this.frame.dim.y),
 | |
|         dx = x - this.frame.dim.x, // shrinking: < 0, expanding: > 0
 | |
|         dy = y - this.frame.dim.y;
 | |
| 
 | |
|     this.frame.coords.x += -dx/2;
 | |
|     this.frame.coords.y += -dy/2;
 | |
|     this.frame.dim.x = x;
 | |
|     this.frame.dim.y = y;
 | |
| 
 | |
|     this.move(dF, dt);
 | |
| 
 | |
|     // fit frame and simulate
 | |
|     this.frame.align(this.px_tile);
 | |
|     var new_tiles = new Vector(this.frame.dim.x / this.px_tile, this.frame.dim.y / this.px_tile);
 | |
|     this.setConfig(new_tiles);
 | |
|     this.updateCells();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| var Game = (function(canvas_id) {
 | |
| 
 | |
|     var canvas = document.getElementById(canvas_id),
 | |
|         ctx = canvas.getContext('2d'),
 | |
| 
 | |
|         // Set up camera and simulation frame
 | |
|         // Camera moves continuously, frame size and coords must fit tiles.
 | |
| 
 | |
|         dim_cam = new Vector(canvas.width, canvas.height),
 | |
|         coords_cam = new Vector(0.0, 0.0), // Initial view: coords_cam -> coords_cam+dim_cam
 | |
| 
 | |
|         px_tile_min = 5, // 5x5 pixels
 | |
|         dim_frame = new Vector(nearestMod0(2*dim_cam.x, px_tile_min), nearestMod0(2*dim_cam.y, px_tile_min)),
 | |
|         coords_frame = new Vector(nearestMod0(coords_cam.x - 0.25*dim_frame.x, px_tile_min), nearestMod0(coords_cam.y - 0.25*dim_frame.y, px_tile_min)),
 | |
|         tiles_frame = new Vector(dim_frame.x/px_tile_min, dim_frame.y/px_tile_min),
 | |
| 
 | |
|         player, enemies = [], organisms = [],
 | |
| 
 | |
|         level0 = [
 | |
|             'player0,55,60',
 | |
|             'enemy0,120,24',
 | |
|             'organism0,-5,0',
 | |
|             'box,120,32',
 | |
|             'diamond,87,32'
 | |
|         ];
 | |
| 
 | |
|         //cells = zeros(tiles_frame.x, tiles_frame.y),
 | |
|         //cells_buf = (tiles_frame.x, tiles_frame.y),
 | |
| 
 | |
| 
 | |
|     // function detectNearbyEnemies(organism) {
 | |
|     //     // Returns a list of indices of nearby enemies
 | |
|     // }
 | |
| 
 | |
|     // function _setOrganismBox(organism, nearby) {
 | |
|     //     // assume all coords are tile fitted
 | |
| 
 | |
|     //     // pos_o = box_coord + 0.5*box
 | |
|     //     var pos_o = Vector(organism.box_coords.x + 0.5*organism.box.x, organism.box_coords.y + 0.5*organism.box.y),
 | |
|     //         old_coords = Vector(organism.box_coords.x, organism.box_coords.y),
 | |
|     //         old_box = Vector(organism.box.x, organism.box.y)
 | |
| 
 | |
|     //     for (var i=0; i<nearby.length; i++) {
 | |
|     //         // Expand boxes x
 | |
|     //         // Expand boxes y
 | |
| 
 | |
|     //         // diff_x =
 | |
| 
 | |
|     //         organism.box_coords.x = Math.min(organism.box_coords.x, nearby[i].box_coords.x);
 | |
|     //         organism.box_coords.y = Math.min(organism.box_coords.y, nearby[i].box_coords.y);
 | |
|     //         organism.box.x = Math.max(organism.box.x+organism.box_coords.x, nearby[i].box.x + nearby[i].box_coords.x - organism.box_coords.x)
 | |
|     //         if ()
 | |
| 
 | |
|     //     }
 | |
|     // }
 | |
| 
 | |
|     // function playerSetBox(player) {
 | |
|     //     // e[] <- find nearby enemies
 | |
|     //     // o[] <- find nearby organisms
 | |
|     //     // new_coords, new_box =
 | |
| 
 | |
|     //     var new_enemies = [], new_organisms = [], d, r;
 | |
| 
 | |
|     //     // Detect nearby enemies
 | |
|     //     // Check distances player-to-all
 | |
|     //     for (var i=0; i<enemies.length; i++) {
 | |
|     //         d = veclen(player.pos.sub(enemies[i].pos));
 | |
|     //         r =
 | |
|     //     }
 | |
|     // }
 | |
| 
 | |
|     // function playerSetBox(player) {
 | |
|     //     // e[] <- find nearby enemies (pops e[])
 | |
|     //     // o[] <- find nearby organisms (pops o[])
 | |
| 
 | |
| 
 | |
|     //     // new_coords, new_box, = findBox(e +  o, )
 | |
| 
 | |
|     //     // player <- new_coords, new_box
 | |
|     //     // updatePlayerConfig(player)
 | |
|     //     player.
 | |
|     // }
 | |
| 
 | |
| 
 | |
|     // function setOrganismBox(organism) {
 | |
|     //     // This has to be a global method because we have to see outside the organisms configuration.
 | |
| 
 | |
| 
 | |
| 
 | |
|     // }
 | |
| 
 | |
|     function addOrganism(configuration, x, y) {
 | |
|         var o = new Organism(configuration, x, y);
 | |
| 
 | |
|         // go through tiles TODO
 | |
|         if (o.isPlayer()) {
 | |
|             player = o;
 | |
|         }
 | |
|         else if (i.isEnemy()) {
 | |
|             enemies.push(i);
 | |
|         }
 | |
|         else {
 | |
|             organisms.push(i);
 | |
|         }
 | |
| 
 | |
|     }
 | |
|     // function drawConfiguration(configuration, x, y) {
 | |
|     //     var tx = Math.min(configuration[0].length, tiles_x-x),
 | |
|     //         ty = Math.min(configuration.length, tiles_y-y);
 | |
| 
 | |
|     //     for (var i=0; i<tx; i++) {
 | |
|     //         for (var j=0; j<ty; j++) {
 | |
|     //             if (configuration[j][i] > 0) {
 | |
|     //                 ctx.fillStyle = cellcol[configuration[j][i]];
 | |
|     //                 ctx.beginPath();
 | |
|     //                 ctx.rect((i+x)*tilesize+0.5, (j+y)*tilesize+0.5, tilesize-0.5, tilesize-0.5);
 | |
|     //                 ctx.closePath();
 | |
|     //                 ctx.fill();
 | |
|     //             }
 | |
|     //         }
 | |
|     //     }
 | |
|     // }
 | |
|     // function update(vx, vy) {
 | |
|     //     updateCells(vx, vy);
 | |
|     // }
 | |
| 
 | |
|     // function drawCells() {
 | |
|     //     for (var i=0; i<tiles_x; i++) {
 | |
|     //         for (var j=0; j<tiles_y; j++) {
 | |
|     //             if (cells[i][j] > 0) {
 | |
|     //                 ctx.fillStyle = cellcol[cells[i][j]];
 | |
|     //                 ctx.beginPath();
 | |
|     //                 ctx.rect(i*tilesize+0.5, j*tilesize+0.5, tilesize-0.5, tilesize-0.5);
 | |
|     //                 ctx.closePath();
 | |
|     //                 ctx.fill();
 | |
|     //             }
 | |
|     //         }
 | |
|     //     }
 | |
|     // }
 | |
| 
 | |
|     // function drawGrid() {
 | |
|     //     ctx.translate(0.5, 0.5); // Transform canvas to get sharp lines
 | |
|     //     ctx.strokeStyle = 'black';
 | |
|     //     ctx.lineWidth = 0.1;
 | |
| 
 | |
|     //     for (var i=1; i<tiles_x; i++) {
 | |
|     //         ctx.beginPath();
 | |
|     //         ctx.moveTo(i*tilesize, 0);
 | |
|     //         ctx.lineTo(i*tilesize, height);
 | |
|     //         ctx.closePath();
 | |
|     //         ctx.stroke();
 | |
|     //     }
 | |
|     //     for (var i=1; i<tiles_y; i++) {
 | |
|     //         ctx.beginPath();
 | |
|     //         ctx.moveTo(0, i*tilesize);
 | |
|     //         ctx.lineTo(width, i*tilesize);
 | |
|     //         ctx.closePath();
 | |
|     //         ctx.stroke();
 | |
|     //     }
 | |
|     //     ctx.setTransform(1, 0, 0, 1, 0, 0); // Transform back
 | |
|     // }
 | |
| 
 | |
|     // function draw() {
 | |
|     //     ctx.clearRect(0, 0, width, height);
 | |
|     //     drawGrid();
 | |
|     //     drawCells();
 | |
|     // }
 | |
|     // function draw2() {
 | |
|     //     ctx.clearRect(0, 0, width, height);
 | |
|     //     drawGrid();
 | |
|     //     for (var i=0; i<organisms.length; i++) {
 | |
|     //         drawConfiguration(organisms[i].config, organisms[i].offset.x, organisms[i].offset.y);
 | |
|     //     }
 | |
|     // }
 | |
| 
 | |
|     // function drawOrganism(organism) {
 | |
|     //     //
 | |
| 
 | |
|     //     var x_t0 = tile_min - (camera.x % tile_min), // x diff from camera to start tile
 | |
|     //         y_t0 = tile_min - (camera.y % tile_min), // x diff from camera to start tile
 | |
|     //         tiles_x = Math.min(organism.config[0].length, tiles_frame.x - x),
 | |
|     //         tiles_y = Math.min(organism.config.length, tiles_frame.y - y);
 | |
| 
 | |
|     //     for (var i=0; i<tiles_x; i++) {
 | |
|     //         for (var j=0; j<tiles_y; j++) {
 | |
|     //             if (organism.config[j][i] > 0) {
 | |
|     //                 ctx.fillStyle = CELL_COL[organism.config[j][i]];
 | |
|     //                 ctx.beginPath();
 | |
| 
 | |
|     //                 // Draw every 5x5 tile at x = (i+x)*tile_min + x_t0,  y = (j+y)*tile_min + y_t0
 | |
|     //                 ctx.rect((i+x)*tile_min+x_t0+0.5, (j+y)*tile_min+y_t0+0.5, tile_min-0.5, tile_min-0.5);
 | |
|     //                 ctx.closePath();
 | |
|     //                 ctx.fill();
 | |
|     //             }
 | |
|     //         }
 | |
|     //     }
 | |
|     // }
 | |
|     function framesOverlap(o1, o2) {
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
|     function minimumDist(o1, o2, d_gap, cell_sep) {
 | |
|         // returns true if o1 and o2 are touching or have a layer of maximum width d_gap consisting only of celltype cell_sep.
 | |
| 
 | |
|         // try finding a layer. If no layer, return true
 | |
|         // try expanding the layer. If d_layer > d_gap return false
 | |
| 
 | |
|     }
 | |
| 
 | |
|     function updatePlayer() {
 | |
|         var new_enemies = [], new_organisms = [];
 | |
| 
 | |
|         // Split player? Implement later
 | |
| 
 | |
|         var gap = 2;
 | |
|         for (var i=0; i<enemies.length; i++) {
 | |
|             if (framesOverlap(player, enemies[i]) && minimumGap(player, enemies[i], 2)) {
 | |
| 
 | |
|             }
 | |
| 
 | |
|             enemies[i].move(player.prev_dF);
 | |
|         }
 | |
|         for (var j=0; j<enemies.length; j++) {
 | |
|            organisms[i].move(dh);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function update(dF) {
 | |
|         //set time
 | |
|         player.move(dF, dh);
 | |
|         for (var i=0; i<enemies.length; i++) {
 | |
|             enemies[i].move(player.prev_dF);
 | |
|         }
 | |
|         //for (var j=0; j<enemies.length; j++) {
 | |
|         //    organisms[i].move(dh);
 | |
|         //}
 | |
| 
 | |
|         updatePlayer();
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     function initLevel(level) {
 | |
|         /*
 | |
|             level = {
 | |
|                 organisms: ['label1,x1,y1', 'label2,x2,y2', ..., 'labeln,xn,yn']
 | |
| 
 | |
|             }
 | |
|         */
 | |
|     }
 | |
|     function shouldMerge(o1, o2, d_gap, cell_t) {
 | |
|         var frame_union = frameUnion(o1.frame, o2.frame);
 | |
|         if (frame_union.isEmpty()) {
 | |
|             return false
 | |
|         }
 | |
| 
 | |
|         // relative speed v_12
 | |
|         var v_12 = new Vector(o1.v.x, o1.v.y);
 | |
|         v_12.sub(o2.v);
 | |
|         if (v_12.dot(o1.v) < 0) {
 | |
|             // Organisms are moving apart
 | |
|             return false
 | |
|         }
 | |
| 
 | |
|         var d_min = Infinity;
 | |
|         // check all-to-all in overlapping region
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|         // Find layer
 | |
|             // find two nearest cells both not of cell cell_t
 | |
|         // expand layer
 | |
|     }
 | |
| 
 | |
| 
 | |
|     function playerMerge() {
 | |
|         var new_enemies = [], new_organisms = [], gap = 2;
 | |
| 
 | |
|         for (var i=0; i<enemies.length; i++) {
 | |
|             if (player.frame.overlaps(enemies[i].frame) && shouldMerge(player, enemies[i], gap, 0)) {
 | |
|                 player.mergeOrganism(enemies[i]);
 | |
|             }
 | |
|             else {
 | |
|                 new_enemies.push(enemies[i]);
 | |
|             }
 | |
|         }
 | |
|         for (var j=0; j<organisms.length; j++) {
 | |
|             if (player.frame.overlaps(organisms[i].frame) && shouldMerge(player, organisms[i], gap, 0)) {
 | |
|                 player.mergeOrganism(organisms[i]);
 | |
|             }
 | |
|             else {
 | |
|                 new_enemies.push(organisms[i]);
 | |
|             }
 | |
|         }
 | |
|         delete new_enemies;
 | |
|         delete organisms;
 | |
|         enemies = new_enemies;
 | |
|         organisms = new_organisms;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     //var t = Date.now(), h = 0, dh = 1; // Start at 1
 | |
|     function step(dF) {
 | |
|         // var t_now = Date.now();
 | |
|         // dt = (t_now - t)/1000;
 | |
|         // t = t_now;
 | |
|         // h += dh;
 | |
| 
 | |
|         var dh = 1; // tmp
 | |
| 
 | |
|         // simulatePlayer
 | |
|         player.move(dF, dh);
 | |
|         player.simulate(dh);
 | |
| 
 | |
|         for (var i=0; i<enemies.length; i++) {
 | |
|             enemies[i].move(player.v, dh);
 | |
|             enemies[i].simulate(dh);
 | |
|         }
 | |
|         for (var j=0; j<organisms.length; j++) {
 | |
|             organisms[i].move(dF, dh);
 | |
|             organisms[j].simulate(dh);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function draw() {
 | |
|         drawOrganism(player); // We have ensured no overlap
 | |
|         for (var i=0; i<enemies.length; i++) {
 | |
|             drawOrganism(enemies[i]);
 | |
|         }
 | |
|         for (var j=0; j<organisms.length; j++) {
 | |
|             drawOrganism(organisms[i]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //function update() {
 | |
|     //    playerMerge();
 | |
| 
 | |
|         //setCamera(player.p, player.v);
 | |
|         //updateFrame();
 | |
|     //}
 | |
| 
 | |
| 
 | |
|     return {
 | |
|         runSimulation: function(timestep) {
 | |
|             _initCells(900);
 | |
|             //insertConfiguration(skintest, 10, 10);
 | |
|             draw();
 | |
|             setInterval(function (){
 | |
|                 update();
 | |
|                 draw();
 | |
|             }, timestep);
 | |
|         },
 | |
|         testphysics: function() {
 | |
|             // Set events
 | |
|             //locatePlayer();
 | |
|             //_initCells(900);
 | |
|             draw2();
 | |
| 
 | |
|             addEventListener('keydown', function(e) {
 | |
|                 var vx = vy = 0,
 | |
|                     key = e.keyCode;
 | |
|                 //locatePlayer();
 | |
|                 if (key == 37) {
 | |
|                     vx--;
 | |
|                 }
 | |
|                 else if (key == 39){
 | |
|                     vx++
 | |
|                 }
 | |
|                 else if (key == 40){
 | |
|                     vy++;
 | |
|                 }
 | |
|                 else if (key == 38) {
 | |
|                     vy--;
 | |
|                 }
 | |
|                 else {
 | |
|                     return
 | |
|                 }
 | |
|                 //movePlayer(vx, vy);
 | |
|                 //updateCells(vx, vy);
 | |
|                 draw2();
 | |
|             })
 | |
|         },
 | |
|         run: function() {
 | |
|             var running = false,
 | |
|                 dF = new Vector(0, 0);
 | |
| 
 | |
|             initLevel(level0);
 | |
|             draw();
 | |
| 
 | |
|             addEventListener('keydown', function(e) {
 | |
|                 if (running) {
 | |
|                     return
 | |
|                 }
 | |
|                 running = true;
 | |
| 
 | |
|                 var key = e.keyCode;
 | |
|                 dF.x = 0;
 | |
|                 dF.y = 0;
 | |
|                 if (key == 37) {
 | |
|                     dF.x--;
 | |
|                 }
 | |
|                 else if (key == 39){
 | |
|                     dF.x++
 | |
|                 }
 | |
|                 else if (key == 40){
 | |
|                     dF.y++;
 | |
|                 }
 | |
|                 else if (key == 38) {
 | |
|                     dF.y--;
 | |
|                 }
 | |
|                 else {
 | |
|                     return
 | |
|                 }
 | |
| 
 | |
|                 update(dF);
 | |
|                 draw();
 | |
|                 running = false;
 | |
|             });
 | |
|         },
 | |
|         addOrganism: addOrganism
 | |
|         //insertConfiguration: insertConfiguration
 | |
|     }
 | |
| });
 | |
| 
 | |
| 
 | |
| // conway
 | |
| // static rule
 | |
| 
 | |
| // CELL MAP
 | |
| /**
 | |
| 0: dead or empty tile
 | |
| 1: solid wall
 | |
| 2: skin cell (player)
 | |
| 3: skin cell (enemy)
 | |
| 4: living cell
 | |
| 4:
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| var game = Game('board');
 | |
| //game.insertConfiguration(skintest, 10, 10);
 | |
| //game.runSimulation(1000);
 | |
| 
 | |
| // game.insertConfiguration(player, 100, 100);
 | |
| // game.insertConfiguration(enemy, 10, 10);
 | |
| 
 | |
| // game.insertConfiguration(box, 56, 12);
 | |
| // game.insertConfiguration(box, 123, 94);
 | |
| // game.insertConfiguration(box, 35, 67);
 | |
| 
 | |
| // game.insertConfiguration(diamond, 43, 122);
 | |
| // game.insertConfiguration(diamond, 86, 12);
 | |
| // game.insertConfiguration(diamond, 25, 75);
 | |
| 
 | |
| // game.insertConfiguration(organism, 94, 55);
 | |
| // game.run();
 | |
| 
 | |
| game.addOrganism(CELL_CONFIGS['organism0'], 94, 55);
 | |
| game.testphysics();
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |