Skip to content

Instantly share code, notes, and snippets.

@Lambdanaut
Created March 10, 2012 22:09
Show Gist options
  • Select an option

  • Save Lambdanaut/2013529 to your computer and use it in GitHub Desktop.

Select an option

Save Lambdanaut/2013529 to your computer and use it in GitHub Desktop.
A Proof of Concept simulation of a bunch of different types of cells that can connect to make larger organisms. Requires JsGameSoup
<html>
<head>
<script src="jsGameSoup/js/jsgamesoup.js"></script>
<script src="jsGameSoup/js/random.js"></script>
<script src="jsGameSoup/js/sprite.js"></script>
<script src="jsGameSoup/js/collisions.js"></script>
<script src="main.js"></script>
</head>
<style>
html, body {
margin: 0px;
padding: 0px;
overflow: hidden;
}
div {
width: 100%;
height: 100%;
position: absolute;
top: -1px;
left: -1px;
}
</style>
<body onload='launch()'>
<div id='surface'></div>
</body>
</html>
bgColor = "rgba(100, 255, 255, 1.0)"
### Bead Widths and Heights ###
bw = 5
bh = 5
### Bead Mass ###
bm = 2
addVector = (pos,vel) -> [ pos[0]+vel[0],pos[1]+vel[1] ]
reverseDir = (dir) ->
switch dir
when 0 then 1
when 1 then 0
when 2 then 3
when 3 then 2
class Game
constructor: (@gs) ->
@world = new World @gs
### Load Art Files ###
Sprite.preload [
"img/nucleus.png",
"img/glue.png",
"img/glueActive.png",
"img/engineN.png",
"img/engineS.png",
"img/engineE.png",
"img/engineW.png"
], () => @gs.addEntity @world
class World
constructor: (@gs) ->
@r = new SeedableRandom()
@beads = []
@currents = []
@populate()
draw: () ->
### @gs.background bgColor ###
update: () ->
### Spawn Currents ###
if @r.nextInt(0,20) == 0
n1 = @r.nextInt(0,2)
if n1 == 0
n1 = -0.1
else n1 = 0.1
n2 = @r.nextInt(0,2)
if n2 == 0
n2 = -0.1
else n2 = 0.1
@currents.push(new Current this, [250,250], [n1,n2], [50,50] )
### Check for Collisions ###
freeBeads = (bead for bead in @beads when bead.palDir is -1)
collide.aabb(freeBeads, @currents)
collide.aabb(@beads,freeBeads)
populate: () ->
@beads = @beads.concat( new Nucleus(this, [@r.nextInt(200,300), @r.nextInt(200,300)] ) for i in [1..20] )
@beads = @beads.concat( new Glue(this, [@r.nextInt(200,300), @r.nextInt(200,300)] ) for i in [1..70] )
@beads = @beads.concat( new Engine(this, [@r.nextInt(200,300), @r.nextInt(200,300)] ) for i in [1..10] )
class Current
constructor: (@world,@pos,@vel,@size) ->
@type = "current"
@world.gs.addEntity this
get_collision_aabb: () -> [@pos[0],@pos[1],@size[0],@size[1] ]
update: () -> @pos = addVector(@pos,@vel)
class Bead
addPal: (pal) ->
if @palDir is -1
maxPals = 4
else maxPals = 3
if @pals.length < maxPals
pal.palDir = @nextPalDir()
pal.p.action "active"
pal.vel = [0,0]
pal.parent = this
pal.lastParent = this.lastParent
@pals.push(pal)
nextPalDir: () ->
if @pals.length is reverseDir(@palDir)
@pals.length + 1
else @pals.length
### Returns an array of this Bead's direct pals ###
getPals: () -> @pals
### Returns an array of all the Beads that make of this Beasty ###
getAllPals: () ->
allPals = @getPals()
if allPals.length == 0
[]
else
allPals.concat( pal.getAllPals() for pal in allPals )
### Keeps your direct pals' position aligned with your own ###
stickPals: () ->
@stickPal pal for pal in @getPals()
stickPal: (pal) ->
### 0,1,2,3 correspond to the North,South,East and West cell ###
switch pal.palDir
when 0 then pal.pos[1] = @pos[1] - bh; pal.pos[0] = @pos[0]
when 1 then pal.pos[1] = @pos[1] + bh; pal.pos[0] = @pos[0]
when 2 then pal.pos[1] = @pos[1]; pal.pos[0] = @pos[0] + bw
when 3 then pal.pos[1] = @pos[1]; pal.pos[0] = @pos[0] - bw
personalUpdate: () ->
### Bead specific collide function. Should be overwritten ###
collide: (who) ->
draw: (c) ->
@p.draw c, @pos
update: () ->
if @palDir is -1
@pos = addVector(@pos,@vel)
@stickPals()
@personalUpdate()
get_collision_aabb: () -> [@pos[0],@pos[1],bw,bh ]
collide_aabb: (who) ->
if who.type == "current"
@vel = addVector(@vel, who.vel)
@collide(who)
class Nucleus extends Bead
constructor: (@world,@pos) ->
@type = "nucleus"
@parent = null
@lastParent = this
@vel = [0,0]
@vision = 50
@pals = []
@palDir = -1
@p = new Sprite ["center", "bottom"]
, neutral: [ ["img/nucleus.png", 1] ]
, active : [ ["img/nucleus.png", 1] ]
, () => @p.action "neutral"
@world.gs.addEntity this
collide: (who) ->
if who.type == "glue" and who.palDir is -1
@addPal who
personalUpdate: () ->
allPals = @getAllPals()
### Inertia ###
for pal in allPals
do (pal) =>
if Math.abs(@vel[0]) < 1
@vel[0] = 0
else @vel[0] /= bm
if Math.abs(@vel[1]) < 1
@vel[1] = 0
alert
else @vel[1] /= bm
class Glue extends Bead
constructor: (@world,@pos) ->
@type = "glue"
@parent = null
@lastParent = null
@vel = [0,0]
@vision = 50
@pals = []
@palDir = -1
@p = new Sprite ["center", "bottom"]
, neutral: [ ["img/glue.png", 0] ]
, active : [ ["img/glueActive.png", 3],["img/glue.png", 3]]
, () => @p.action "neutral"
@world.gs.addEntity this
collide: (who) ->
if (who.type == "glue" or who.type == "engine") and who.palDir is -1 and @palDir isnt -1
@addPal who
class Engine extends Bead
constructor: (@world,@pos) ->
@type = "engine"
@parent = null
@lastParent = null
@vel = [0,0]
@vision = 50
@pals = []
@palDir = -1
@p = new Sprite ["center", "bottom"]
, neutral: [ ["img/engineN.png", 0] ]
, neutralS: [ ["img/engineS.png", 0] ]
, neutralE: [ ["img/engineE.png", 0] ]
, neutralW: [ ["img/engineW.png", 0] ]
, active : [ ["img/engineN.png", 0] ]
, () => @p.action "neutral"
@world.gs.addEntity this
personalUpdate: () ->
switch @palDir
when 0
@p.action "neutral"
@lastParent.vel[1] += 3
when 1
@p.action "neutralS"
@lastParent.vel[1] -= 3
when 2
@p.action "neutralE"
@lastParent.vel[0] -= 3
when 3
@p.action "neutralW"
@lastParent.vel[0] += 3
window.launch = () ->
surface = document.getElementById("surface")
newCanvas = document.createElement("canvas")
newCanvas.style.width = newCanvas.width = surface.offsetWidth + 1
newCanvas.style.height = newCanvas.height = surface.offsetHeight + 1
surface.appendChild newCanvas
gs = new JSGameSoup newCanvas, 30
new Game gs
gs.launch()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment