Permalink
Browse files

new life engine impl based on array map

  • Loading branch information...
1 parent d3a4998 commit d021b72a34381bb230acfb69aafa43b0c9f4afda @theoxylo committed Apr 8, 2013
Showing with 121 additions and 64 deletions.
  1. 0 README.md
  2. +2 −2 Voxel.js
  3. +2 −2 controller.pie
  4. +22 −16 index.js
  5. +91 −26 life-engine.js
  6. +2 −5 package.json
  7. +0 −11 server.js
  8. +2 −2 voxel-clipboard.js
View
0 README.md 100755 → 100644
No changes.
View
@@ -4,7 +4,7 @@ function Voxel(pos, material) {
if (!(this instanceof Voxel)) {
console.log("warning: Voxel called without 'new' keyword")
- return new Voxel(pos)
+ return new Voxel(pos, material)
}
return {
@@ -15,4 +15,4 @@ function Voxel(pos, material) {
, material: 0 || material
}
-}
+}
View
@@ -16,8 +16,8 @@ Key.R = Joystick1.Button4 // Btn Y -- 1st/3rd person view
Key.T = Joystick1.Button6 // RB -- rotate copied selection
//Key.W = Joystick1.Button7 // Back button - randomize GoL
Key.Escape = Joystick1.Button8 // Start button - release mouse
-Key.I = Joystick1.Button9 // LS Click - toggle select mode
-Key.H = Joystick1.Button10 // RS Click - toggle adjacent
+Key.H = Joystick1.Button9 // LS Click - toggle adjacent
+Key.I = Joystick1.Button10 // RS Click - toggle select mode
// Mouse Clicks
Mouse.LeftButton = EnsureMapRange(Joystick1.z, 0,-1, 0,1) //RT
View
@@ -1,4 +1,3 @@
-var voxel = require('voxel')
var createGame = require('voxel-engine')
var highlight = require('voxel-highlight')
var createPlayer = require('voxel-player')
@@ -33,12 +32,17 @@ function createNonRepeater(keyControl, fn) {
}
var game = createGame( {
- generate: function (x, y, z) {
- (y % 16 === 0) ? Math.ceil(Math.random() * 2) // repeating levels of grass and obsidian
+ generateOld: function (x, y, z) {
+ return (y % 16 === 0) ? Math.ceil(Math.random() * 2) // repeating levels of grass and obsidian
: (x === 0 && y === 1 && z === 0) ? 3 // brick
: (x === 1 && y === 1 && z === 0) ? 4 // plank
: 0 // empty
},
+ generate: function (x, y, z) {
+ return (y === 10 && Math.abs(x) < 1 && Math.abs(z) < 1) ? 3 // platform for player
+ : (y === 0 && Math.abs(x) <= 32 && Math.abs(z) <= 32) ? 1 // expanse of grass same size as life board
+ : 0
+ },
keybindings: {
'W': 'forward'
, 'A': 'left'
@@ -51,7 +55,7 @@ var game = createGame( {
, 'E': 'select_paste'
, 'Y': 'select_export'
, 'T': 'select_rotate'
- , 'O': 'life_randomize'
+ , 'O': 'life_reset'
, 'P': 'life_pause'
, '<mouse 1>': 'fire'
, '<mouse 2>': 'firealt'
@@ -78,8 +82,8 @@ game.appendTo(document.body)
// add the player
var player = createPlayer(game)('img/player.png', { gravity: true })
player.possess()
-player.yaw.position.set(2, 14, 4)
-var triggerView = createNonRepeater('view', player.toggle.bind(player));
+player.yaw.position.set(0, 14, 0)
+var triggerView = createNonRepeater('view', player.toggle.bind(player))
// highlight blocks when you look at them
var blockPosPlace, blockPosErase
@@ -89,7 +93,7 @@ var highlighter = highlight(game, {
, adjacentActive: createToggler('adjacent')
, selectActive: createToggler('select')
, animate: true
-});
+})
highlighter.on('highlight', function (voxelPos) { blockPosErase = voxelPos })
highlighter.on('remove', function (voxelPos) { blockPosErase = null })
highlighter.on('highlight-adjacent', function (voxelPos) { blockPosPlace = voxelPos })
@@ -116,26 +120,28 @@ var triggerExport = createNonRepeater('select_export')
var triggerRotate = createNonRepeater('select_rotate')
// GoL support, life engine wrapper
-var life = require('./life-engine')(game, { tickTime: 250 } )
-life.randomize()
+var life = require('./life-engine')(game, { tickTime: 200 } )
+life.reset()
life.resume()
-var triggerLifeRandomize = createNonRepeater('life_randomize', life.randomize)
+var triggerLifeReset = createNonRepeater('life_reset', life.reset)
var triggerLifePause = createNonRepeater('life_pause', life.togglePause)
// main update function, called at about 60 hz
-game.on('tick', function onUpdate(dt) {
+game.on('tick', onUpdate)
+
+function onUpdate(dt) {
if (triggerCopy() && selection) {
- clipboard.copy(selection.start, selection.end);
+ clipboard.copy(selection.start, selection.end)
}
else if (triggerPaste()) {
- clipboard.paste(highlighter.currVoxelAdj || highlighter.currVoxelPos, selection);
+ clipboard.paste(highlighter.currVoxelAdj || highlighter.currVoxelPos, selection)
life.readVoxels()
}
if (triggerRotate()) clipboard.rotateAboutY()
- if (triggerExport() && selection) {
+ if (triggerExport()) {
var exportedData = JSON.stringify(clipboard.exportData())
console.log(exportedData)
alert("Selection data: " + exportedData)
@@ -144,10 +150,10 @@ game.on('tick', function onUpdate(dt) {
triggerView() // 1st vs 3rd person view
// game of life triggers
- triggerLifeRandomize()
+ triggerLifeReset()
triggerLifePause()
life.tick(dt) // iterate life engine
-})
+}
highlighter.on('highlight-select', function (s) {
selection = s
View
@@ -1,13 +1,17 @@
-var Life = require('alive')
-
module.exports = function createInstance(game, opts) {
opts = opts || {}
- var boardPos = opts.boardPosition || [-32, 0, -32]
+ var on_material = 2 || opts.on_material
+ var off_material = 0 || opts.off_material
+ var boardPos = opts.boardPosition || [-32, 1, -32]
var boardSize = opts.boardSize || 64
var tickTime = opts.tickTime || 500
var timeSinceTick = 0
var paused = false
- var instance = new Life(boardSize)
+ var cells = new Array(boardSize * boardSize)
+
+ function addCell(cell) {
+ cells[cell.x * boardSize + cell.z] = cell
+ }
function pause() {
if (paused) return
@@ -24,57 +28,118 @@ module.exports = function createInstance(game, opts) {
paused = false
}
- function randomize() {
+ function reset() {
pause()
+
+ // clear life cells and voxels
+ cells = []
for (var i = 0; i < boardSize; i++) {
for (var j = 0; j < boardSize; j++) {
- // random cell state 1 (grass) or 2 (obsidian)
- instance.setCell(i, j, Math.random() > 0.5 ? 1 : 0)
+ var pos = [boardPos[0] + i, boardPos[1], boardPos[2] + j]
+ game.setBlock(pos, off_material)
}
}
- paint()
+
+ // add glider cells
+ addCell( { x: 0, z: 0, on: true } )
+ addCell( { x: 0, z: 1, on: true } )
+ addCell( { x: 0, z: 2, on: true } )
+ addCell( { x: 1, z: 2, on: true } )
+ addCell( { x: 2, z: 1, on: true } )
+
+ updateVoxels()
}
function readVoxels() {
console.log('readVoxels')
- for (var i = 0; i < boardSize; i++) {
- for (var j = 0; j < boardSize; j++) {
- var pos = [boardPos[0] + i, boardPos[1], boardPos[2] + j]
- // voxel material 2 (obsidian) is active life cell
- instance.setCell(i, j, game.getBlock(pos) === 2 ? 1 : 0)
+ for (var x = 0; x < boardSize; x++) {
+ for (var z = 0; z < boardSize; z++) {
+ var pos = [boardPos[0] + x, boardPos[1], boardPos[2] + z]
+ if (game.getBlock(pos) === on_material) {
+ addCell( { x: x, z: z, on: true } )
+ }
}
}
- paint()
}
function tick(dt) {
if (paused) return;
timeSinceTick += dt
if (timeSinceTick > tickTime) {
timeSinceTick = 0
- instance.tick() // slow? need partial tick without paint
- paint()
- }
- }
- function paint() {
- for (var i = 0; i < boardSize; i++) {
- for (var j = 0; j < boardSize; j++) {
- var pos = [boardPos[0] + i, boardPos[1], boardPos[2] + j]
- game.setBlock(pos, instance.getCell(i, j) ? 2 : 1)
+ // remove inactive cells
+ cells = cells.map(function (cell) {
+ return cell && cell.on ? cell : undefined
+ })
+
+ var possibleNewCells = []
+
+ cells.forEach(function (cell) {
+ if (!cell) return
+ // check each of 8 neighbors:
+ // if a neighbor is active, increment counter
+ // otherwise, save for later to check for new cell
+ var count = 0 // number of live neighbors
+ for (var dx = -1; dx < 2; dx++) {
+ for (var dz = -1; dz < 2; dz++) {
+ if (dx === 0 && dz === 0) continue
+ var empty = getEmptyNeighbor(cell.x, cell.z, dx, dz)
+ if (empty) possibleNewCells.push(empty)
+ else count++
+ }
+ }
+ if (count < 2 || count > 3) cell.on = false
+ })
+
+ possibleNewCells.map(function (cell) {
+ var count = 0 // number of live neighbors
+ for (var dx = -1; dx < 2; dx++) {
+ for (var dz = -1; dz < 2; dz++) {
+ if (dx === 0 && dz === 0) continue
+ var empty = getEmptyNeighbor(cell.x, cell.z, dx, dz)
+ if (!empty) count++
+ }
+ }
+ if (count === 3) return cell // a new cell is born
+ return undefined
+ }).forEach(function (cell) {
+ if (!cell) return
+ cell.on = true
+ addCell(cell)
+ })
+
+ function getEmptyNeighbor(x, z, dx, dz) {
+ var x_coord = (x + dx) % boardSize
+ if (x_coord < 0) x_coord += boardSize
+
+ var z_coord = (z + dz) % boardSize
+ if (z_coord < 0) z_coord += boardSize
+
+ if (cells[x_coord * boardSize + z_coord]) return false
+ return { x: x_coord, z: z_coord, on: false }
}
+
+ updateVoxels()
}
}
+ function updateVoxels() {
+ cells.forEach(function (cell) {
+ if (!cell) return
+ var pos = [boardPos[0] + cell.x, boardPos[1], boardPos[2] + cell.z]
+ game.setBlock(pos, cell.on ? on_material : off_material)
+ })
+ }
+
// public api:
return {
pause: pause,
togglePause: togglePause,
resume: resume,
- randomize: randomize,
+ reset: reset,
tick: tick,
- readVoxels: readVoxels,
- paint: paint
+ readVoxels: readVoxels
}
}
View
@@ -1,23 +1,20 @@
{
"name": "voxel-life",
- "version": "0.0.3",
+ "version": "0.0.4",
"repository": {
"type":"git",
"url": "git@github.com:theoxylo/voxel-life.git"
},
"dependencies": {
- "alive": "0.0.2",
"painterly-textures": "0.0.3",
- "voxel": "0.3.1",
"voxel-engine": "0.16.3",
"voxel-highlight": "0.0.9",
"voxel-player": "0.1.0"
},
"devDependencies": {
"browserify": "2.7.3",
"browservefy": "0.0.10",
- "ecstatic": "0.4.2",
- "node-static": "0.6.7"
+ "ecstatic": "0.4.2"
},
"scripts": {
"start": "browservefy index.js:bundle.js 8080 -- -dv"
View
@@ -1,14 +1,3 @@
-// var StaticServer = require('node-static').Server
-//
-// var staticServer = new StaticServer('./')
-//
-// require('http').createServer(function(request, response) {
-// request.addListener('end', function() {
-// console.log(request.url)
-// staticServer.serve(request, response)
-// })
-// }).listen(8080)
-
var http = require('http');
var ecstatic = require('ecstatic');
View
@@ -1,4 +1,4 @@
-var Voxel = require('./Voxel')
+var Vooxel = require('./Voxel')
module.exports = Clipboard
@@ -34,7 +34,7 @@ Clipboard.prototype.copy = function (start, end) {
for (var k = 0; k < this.dims[2]; k++) {
// store voxel block material index, 0 for none
var material = this.game.getBlock([x_min + i, y_min + j, z_min + k])
- newSelectionData[index++] = new Voxel([i, j, k], material)
+ newSelectionData[index++] = new Vooxel([i, j, k], material)
}
}
}

0 comments on commit d021b72

Please sign in to comment.