Skip to content

Commit d0ad077

Browse files
committed
split into separate files
split some functions off into cell.lua and defs.lua
1 parent 9ae79c9 commit d0ad077

File tree

3 files changed

+393
-388
lines changed

3 files changed

+393
-388
lines changed

cell.lua

+383
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,383 @@
1+
love.filesystem.load("defs.lua")()
2+
function newCell(x, y)
3+
cell = {}
4+
cell.nucleus = {x=x,y=y,vx=0,vy=0,ax=0,ay=0}
5+
6+
cell.membrane = {}
7+
for i = 1, 23, 2 do
8+
cell.membrane[i] = x+50*math.cos(math.rad(15*i))
9+
cell.membrane[i+1] = y+50*math.sin(math.rad(15*i))
10+
end
11+
cell.mbsize = table.getn(cell.membrane)
12+
13+
cell.springs = {}
14+
for i = 1,13 do cell.springs[i] = fNucSpringLength(cell) end
15+
cell.membraneVel = { }
16+
for i = 1,cell.mbsize do
17+
cell.membraneVel[i] = 0 --set initial velocities to zero
18+
end
19+
--membraneVel[1] = 0.5
20+
--membraneVel[2] = 0.5
21+
cell.membraneAcc = { }
22+
for i = 1,cell.mbsize do
23+
cell.membraneAcc[i] = 0 --set initial acceleration to zero
24+
end
25+
cell.genes = {}
26+
cell.genes.growtime = 2 --1 --time to grow a new node, in seconds
27+
cell.genes.splitnodes = 18 --18 --# membrane nodes to divide at
28+
cell.genes.speed = 15 --15 --movement speed
29+
cell.genes.attackdist = 100 --how close it has to be to player to attack
30+
cell.genes.bombgrav = 0 --how attracted (+) or repelled (-) it is by bombs
31+
cell.genes.attackstyle = "bump" --either "bump" or "engulf"
32+
cell.genes.acidity = 0 --how much player is damaged when inside cell
33+
cell.genes.damagestyle = "shrink" --either "shrink" or "split"
34+
35+
cell.gtimer = 0 --in seconds
36+
cell.dir = math.random()*2*math.pi --movement direction
37+
38+
return cell
39+
end
40+
41+
function mutate(c)
42+
local g = c.genes
43+
--g.growtime = g.growtime + (math.random()-0.5)*0.01
44+
if 1 == math.random(10) then g.growtime = g.growtime + math.random(3) - 2 end
45+
if(g.growtime < 0.1) then g.growtime = 0.1 end
46+
if 1 == math.random(6) then g.splitnodes = g.splitnodes + 2*(math.random(3) - 2) end
47+
if(g.splitnodes < 12) then g.splitnodes = 12 end
48+
--g.speed = g.speed + (math.random()-0.5)
49+
--g.attackdist = g.attackdist + (math.random()-0.5)*10
50+
--c.genes.bombgrav = 0
51+
--c.genes.attackstyle = "bump"
52+
--g.acidity = g.acidity + math.random(-5,5)
53+
--c.genes.damagestyle = "shrink"
54+
end
55+
56+
function updateCell(_n,dt)
57+
local c = cells[_n]
58+
--print(_n,c)
59+
--print(c.membrane[1],c.membrane[2],c.membrane[mbsize-1],c.membrane[mbsize])
60+
--print(c.nucleus.x,c.nucleus.y,c.nucleus.vx,c.nucleus.vy,c.nucleus.ax,c.nucleus.ay)
61+
c.gtimer = c.gtimer + dt
62+
if c.gtimer >= c.genes.growtime then --grow
63+
c.gtimer = c.gtimer - c.genes.growtime --reset timer
64+
--insert new node into random part of membrane:
65+
local idx = math.random(c.mbsize-1)
66+
local idx2 = idx - 2
67+
if idx2 < 1 then idx2 = c.mbsize-1 end
68+
local nx = (c.membrane[idx2]+c.membrane[idx])/2 -- average of surrounding node x coords
69+
local ny = (c.membrane[idx2+1]+c.membrane[idx+1])/2 -- " " y coords
70+
table.insert(c.membrane,idx,nx)
71+
table.insert(c.membrane,idx+1,ny)
72+
local nvx = (c.membraneVel[idx2]+c.membraneVel[idx])/2 -- average of surrounding node vx coords
73+
local nvy = (c.membraneVel[idx2+1]+c.membraneVel[idx+1])/2 -- " " vy coords
74+
table.insert(c.membraneVel,idx,nvx)
75+
table.insert(c.membraneVel,idx+1,nvy)
76+
local nodax = (c.membraneAcc[idx2]+c.membraneAcc[idx])/2 -- average of surrounding node ax coords
77+
local noday = (c.membraneAcc[idx2+1]+c.membraneAcc[idx+1])/2 -- " " ay coords
78+
table.insert(c.membraneAcc,idx,nodax)
79+
table.insert(c.membraneAcc,idx+1,noday)
80+
--add spring to nucleus:
81+
table.insert(c.springs,(idx+1)/2,fNucSpringLength(c))
82+
c.mbsize = table.getn(c.membrane)
83+
end
84+
85+
--BEGIN MITOSIS:
86+
if c.mbsize/2 >= c.genes.splitnodes then --mitosis!
87+
--[[io.write("c: {")
88+
for itr = 1,c.mbsize do io.write(c.membrane[itr]," ") end
89+
io.write("}\n")]]
90+
local split = (c.mbsize/2)+1 --divide in two; currently just midpoint; should do random split maybe?
91+
print("split:",split)
92+
local oldc = c
93+
io.write("oldc: {")
94+
for itr = 1,oldc.mbsize do io.write(oldc.membrane[itr]," ") end
95+
io.write("}\n")
96+
--print(oldc)
97+
c = {}
98+
c.membrane = {}
99+
--print(c,oldc)
100+
c.membraneVel = {}
101+
c.membraneAcc = {}
102+
c.springs = {}
103+
c.nucleus = {}
104+
local newcell = {}
105+
newcell.membrane = {}
106+
newcell.membraneVel = {}
107+
newcell.membraneAcc = {}
108+
newcell.springs = {}
109+
newcell.nucleus = {}
110+
for i = 1,split-1 do
111+
--print(oldc.membrane[i])
112+
c.membrane[i] = oldc.membrane[i]
113+
--print(c.membrane[i])
114+
c.membraneVel[i] = oldc.membraneVel[i]
115+
c.membraneAcc[i] = oldc.membraneAcc[i]
116+
--[[if (math.floor(i/2) ~= i/2) then
117+
c.springs[(i+1)/2] = oldc.springs[(i+1)/2]
118+
end]]
119+
end
120+
for i = split,oldc.mbsize do
121+
newcell.membrane[i+1-split] = oldc.membrane[i]
122+
--print(newcell.membrane[i+1-split])
123+
newcell.membraneVel[i+1-split] = oldc.membraneVel[i]
124+
newcell.membraneAcc[i+1-split] = oldc.membraneAcc[i]
125+
--[[if (math.floor(i/2) ~= i/2) then
126+
newcell.springs[(i+2-split)/2] = oldc.springs[(i+1)/2]
127+
end]]
128+
--[[table.insert(newcell.membrane,i,table.remove(c.membrane,i))
129+
table.insert(newcell.membraneVel,i,table.remove(c.membraneVel,i))
130+
table.insert(newcell.membraneAcc,i,table.remove(c.membraneAcc,i))
131+
if (math.floor(i/2) ~= i/2) then --since springs array has half as many elements
132+
table.insert(newcell.springs,(i+1)/2,table.remove(c.springs,(i+1)/2))
133+
end]]
134+
end
135+
--add extra node
136+
c.membrane[split] = oldc.nucleus.x
137+
c.membrane[split+1] = oldc.nucleus.y
138+
c.membraneVel[split] = oldc.nucleus.vx
139+
c.membraneVel[split+1] = oldc.nucleus.vy
140+
c.membraneAcc[split] = oldc.nucleus.ax
141+
c.membraneAcc[split+1] = oldc.nucleus.ay
142+
143+
--[[newcell.membrane[oldc.mbsize+1-split] = oldc.nucleus.x
144+
newcell.membrane[oldc.mbsize+1-split+1] = oldc.nucleus.y
145+
newcell.membraneVel[(oldc.mbsize+1)-split] = oldc.nucleus.vx
146+
newcell.membraneVel[(oldc.mbsize+2)-split] = oldc.nucleus.vy
147+
newcell.membraneAcc[(oldc.mbsize+1)-split] = oldc.nucleus.ax
148+
newcell.membraneAcc[(oldc.mbsize+2)-split] = oldc.nucleus.ay]]
149+
150+
c.mbsize = table.getn(c.membrane)
151+
for itr = 1,c.mbsize/2 do c.springs[itr] = fNucSpringLength(c) end
152+
io.write("c: {")
153+
for itr = 1,c.mbsize do io.write(c.membrane[itr]," ") end
154+
io.write("}\n")
155+
newcell.mbsize = table.getn(newcell.membrane)
156+
157+
newcell.membrane[newcell.mbsize+1] = oldc.nucleus.x
158+
newcell.membrane[newcell.mbsize+2] = oldc.nucleus.y
159+
newcell.membraneVel[newcell.mbsize+1] = oldc.nucleus.vx
160+
newcell.membraneVel[newcell.mbsize+2] = oldc.nucleus.vy
161+
newcell.membraneAcc[newcell.mbsize+1] = oldc.nucleus.ax
162+
newcell.membraneAcc[newcell.mbsize+2] = oldc.nucleus.ay
163+
164+
newcell.mbsize = table.getn(newcell.membrane)
165+
for itr = 1,newcell.mbsize/2 do newcell.springs[itr] = fNucSpringLength(newcell) end
166+
print("n mbsz",newcell.mbsize)
167+
io.write("newcell: {")
168+
for itr = 1,newcell.mbsize do io.write(newcell.membrane[itr]," ") end
169+
io.write("}\n")
170+
local cnx = 0
171+
local cny = 0
172+
local j = 1
173+
while j < c.mbsize do
174+
cnx = cnx + c.membrane[j]
175+
cny = cny + c.membrane[j+1]
176+
j = j + 2
177+
end
178+
--[[newcell.nucleus.x = cnx/(c.mbsize/2)
179+
newcell.nucleus.y = cny/(c.mbsize/2)]]
180+
c.nucleus.x = cnx/(c.mbsize/2)
181+
c.nucleus.y = cny/(c.mbsize/2)
182+
c.nucleus.vx = oldc.nucleus.vx -- / 2
183+
c.nucleus.vy = oldc.nucleus.vy -- / 2
184+
c.nucleus.ax = oldc.nucleus.ax --0
185+
c.nucleus.ay = oldc.nucleus.ay --0
186+
local nnx = 0
187+
local nny = 0
188+
local j = 1
189+
while j < newcell.mbsize do
190+
nnx = nnx + newcell.membrane[j]
191+
nny = nny + newcell.membrane[j+1]
192+
j = j + 2
193+
end
194+
--[[c.nucleus.x = nnx/(newcell.mbsize/2)
195+
c.nucleus.y = nny/(newcell.mbsize/2)]]
196+
newcell.nucleus.x = nnx/(newcell.mbsize/2)
197+
newcell.nucleus.y = nny/(newcell.mbsize/2)
198+
newcell.nucleus.vx = oldc.nucleus.vx -- / 2
199+
newcell.nucleus.vy = oldc.nucleus.vy -- / 2
200+
newcell.nucleus.ax = oldc.nucleus.ax --0
201+
newcell.nucleus.ay = oldc.nucleus.ay --0
202+
203+
--TODO: mutations
204+
c.genes = {}
205+
c.gtimer = 0
206+
newcell.genes = {}
207+
newcell.gtimer = 0
208+
209+
for k,v in pairs(oldc.genes) do
210+
c.genes[k] = v
211+
newcell.genes[k] = v
212+
end
213+
214+
mutate(c)
215+
mutate(newcell)
216+
--c.genes.acidity = c.genes.acidity + math.random(-5,5)
217+
--newcell.genes.acidity = newcell.genes.acidity + math.random(-5,5)
218+
219+
c.dir = math.random()*2*math.pi
220+
newcell.dir = math.random()*2*math.pi
221+
222+
cells[_n] = c
223+
--[[nCells = nCells + 1
224+
cells[nCells] = newcell]]
225+
table.insert(cells,newcell)
226+
end
227+
--END MITOSIS.
228+
229+
--c.nucleus acc
230+
local nax = 0
231+
local nay = 0
232+
233+
--acceleration for constant speed
234+
local acc = mediumDamping * c.genes.speed
235+
236+
if distance(c.nucleus.x,c.nucleus.y,player.x,player.y) <= c.genes.attackdist then
237+
c.dir = math.atan2(player.y-c.nucleus.y,player.x-c.nucleus.x)
238+
end
239+
local dir = c.dir
240+
--[[if love.keyboard.isDown("right","f","left","s","down","d","up","e") then
241+
acc = mediumDamping * c.genes.speed
242+
if love.keyboard.isDown("right","f") then dir = 0 end
243+
if love.keyboard.isDown("left","s") then dir = math.pi end
244+
if love.keyboard.isDown("down","d") then dir = 0.5*math.pi end
245+
if love.keyboard.isDown("up","e") then dir = 1.5*math.pi end
246+
end]]
247+
nax = nax + acc*math.cos(dir)
248+
nay = nay + acc*math.sin(dir)
249+
250+
local avgx = 0
251+
local avgy = 0
252+
--Verlet integration
253+
local i = 1
254+
while i < c.mbsize do
255+
local continue = false
256+
local newax = 0
257+
local neway = 0
258+
avgx = avgx + c.membrane[i]
259+
avgy = avgy + c.membrane[i+1]
260+
--check for COLLISIONS:
261+
--with player:
262+
if distance(c.membrane[i],c.membrane[i+1],player.x,player.y) < plen+2 then
263+
hitPlayer(1)
264+
table.insert(debugPts,{x = c.membrane[i], y = c.membrane[i+1], r = 2})
265+
table.insert(debugPts,{x = c.nucleus.x, y = c.nucleus.y, r = 4})
266+
end
267+
--with bullets:
268+
local j = 1
269+
while j <= table.getn(bullets) do
270+
if distance(c.membrane[i],c.membrane[i+1],bullets[j].x,bullets[j].y) < 4 then
271+
272+
table.insert(debugPts,{x = c.membrane[i], y = c.membrane[i+1], r = 2})
273+
table.insert(debugPts,{x = c.nucleus.x, y = c.nucleus.y, r = 4})
274+
275+
table.remove(bullets,j)
276+
table.remove(c.membrane,i)
277+
table.remove(c.membrane,i)
278+
table.remove(c.membraneVel,i)
279+
table.remove(c.membraneVel,i)
280+
table.remove(c.membraneAcc,i)
281+
table.remove(c.membraneAcc,i)
282+
table.remove(c.springs,(i+1)/2)
283+
c.mbsize = table.getn(c.membrane)
284+
continue = true
285+
break
286+
else
287+
j = j + 1
288+
end
289+
end
290+
if not continue then
291+
--update position:
292+
--print(i,c.mbsize)
293+
c.membrane[i] = c.membrane[i] + c.membraneVel[i]*dt + 0.5*c.membraneAcc[i]*dt*dt --update x
294+
c.membrane[i+1] = c.membrane[i+1] + c.membraneVel[i+1]*dt + 0.5*c.membraneAcc[i+1]*dt*dt --update y
295+
--boundaries:
296+
if c.membrane[i] < xmin then c.membrane[i] = xmin+2; c.dir = c.dir + math.pi
297+
elseif c.membrane[i] > xmax then c.membrane[i] = xmax-2; c.dir = c.dir + math.pi end
298+
if c.membrane[i+1] < ymin then c.membrane[i+1] = ymin+2; c.dir = c.dir + math.pi
299+
elseif c.membrane[i+1] > ymax then c.membrane[i+1] = ymax-2; c.dir = c.dir + math.pi end
300+
--calculating acceleration:
301+
302+
local accn = acc + 80*(math.random() - 0.5)
303+
newax = newax + accn*math.cos(dir)
304+
neway = neway + accn*math.sin(dir)
305+
306+
--print(c.springs[(i+1)/2])
307+
308+
--Hooke's law for spring connecting c.membrane point to c.nucleus:
309+
local distance = math.sqrt((c.membrane[i]-c.nucleus.x)^2 + (c.membrane[i+1]-c.nucleus.y)^2)
310+
local force = -kNucSpring*(distance-c.springs[(i+1)/2]) -- -kNucSpring*(distance-nucSpringLength)
311+
--if 1 == i or 13 == i then force = -kNucSpring*(distance-nucSpringLength*1.75) end
312+
local theta = math.atan2(c.membrane[i+1]-c.nucleus.y,c.membrane[i]-c.nucleus.x)
313+
newax = newax + (force/distance)*math.cos(theta)
314+
neway = neway + (force/distance)*math.sin(theta)
315+
nax = nax - --[[0.5*]](force/distance)*math.cos(theta)
316+
nay = nay - --[[0.5*]](force/distance)*math.sin(theta)
317+
318+
--Hooke's law for springs connecting to adjacent points:
319+
--preceding:
320+
local otherx = 0
321+
local othery = 0
322+
--print(i,c.mbsize)
323+
if 1 == i then
324+
otherx = c.membrane[c.mbsize-1]
325+
othery = c.membrane[c.mbsize]
326+
else
327+
otherx = c.membrane[i-2]
328+
othery = c.membrane[i-1]
329+
end
330+
distance = math.sqrt((c.membrane[i]-otherx)^2 + (c.membrane[i+1]-othery)^2)
331+
force = -kMemSpring*(distance-memSpringLength)
332+
theta = math.atan2(c.membrane[i+1]-othery,c.membrane[i]-otherx)
333+
newax = newax + (force/distance)*math.cos(theta)
334+
neway = neway + (force/distance)*math.sin(theta)
335+
336+
--succeeding:
337+
if c.mbsize-1 == i then
338+
otherx = c.membrane[1]
339+
othery = c.membrane[2]
340+
else
341+
otherx = c.membrane[i+2]
342+
othery = c.membrane[i+3]
343+
end
344+
distance = math.sqrt((c.membrane[i]-otherx)^2 + (c.membrane[i+1]-othery)^2)
345+
force = -kMemSpring*(distance-memSpringLength)
346+
theta = math.atan2(c.membrane[i+1]-othery,c.membrane[i]-otherx)
347+
newax = newax + (force/distance)*math.cos(theta)
348+
neway = neway + (force/distance)*math.sin(theta)
349+
350+
--damping:
351+
newax = newax - mediumDamping*c.membraneVel[i]
352+
neway = neway - mediumDamping*c.membraneVel[i+1]
353+
354+
--update velocity:
355+
c.membraneVel[i] = c.membraneVel[i] + (c.membraneAcc[i]+newax)*dt/2 --update vx
356+
c.membraneVel[i+1] = c.membraneVel[i+1] + (c.membraneAcc[i+1]+neway)*dt/2 --update vy
357+
c.membraneAcc[i] = newax
358+
c.membraneAcc[i+1] = neway
359+
i = i + 2
360+
end--if not continue; hackish workaround since Lua apparently doesn't have continue
361+
end
362+
363+
avgx = avgx / table.getn(c.membrane)
364+
avgy = avgy / table.getn(c.membrane)
365+
366+
--[[if distance(avgx,avgy,c.nucleus.x,c.nucleus.y) > nucSpringLength then
367+
c.nucleus.x = avgx
368+
c.nucleus.y = avgy
369+
end]]
370+
371+
--c.nucleus motion: (verlet)
372+
c.nucleus.x = c.nucleus.x + c.nucleus.vx*dt + 0.5*c.nucleus.ax*dt*dt
373+
c.nucleus.y = c.nucleus.y + c.nucleus.vy*dt + 0.5*c.nucleus.ay*dt*dt
374+
375+
--damping:
376+
c.nucleus.ax = c.nucleus.ax - mediumDamping*c.nucleus.vx
377+
c.nucleus.ay = c.nucleus.ay - mediumDamping*c.nucleus.vy
378+
379+
c.nucleus.vx = c.nucleus.vx + (c.nucleus.ax+nax)*dt/2
380+
c.nucleus.vy = c.nucleus.vy + (c.nucleus.ay+nay)*dt/2
381+
c.nucleus.ax = nax
382+
c.nucleus.ay = nay
383+
end

defs.lua

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function distance(x1,y1,x2,y2)
2+
return math.sqrt((x2-x1)^2 + (y2-y1)^2)
3+
end

0 commit comments

Comments
 (0)