Created
July 8, 2020 04:40
-
-
Save bened-h/e44cb5348e6d7c2dd72dea494b04edea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# blender 2.8 | |
""" | |
This script implements Convey's "Game of Life" in Blender 2.8 | |
It relies on the blender file containing a mesh called "Cube" | |
(sidelength = 1) and an empty collection called "Grid". | |
# original code: https://gist.github.com/bened-h/9d56a03e9a14b917980c1d4039bf1687 | |
# inspired by this comment https://www.reddit.com/r/generative/comments/ghuvlg/i_made_a_25dimensional_version_of_conways_game_of/fqb5nlu/ | |
""" | |
import bpy | |
from math import log | |
from random import random | |
gridsize = 20 # number of tiles in the grid (x/y-axis) | |
tile_size = 10./gridsize # the number descirbes grid dimension | |
time_stretch = 3 # distance between keyframes (iteration steps) | |
class Tile(): | |
grid = [[None for x in range(gridsize)] for y in range(gridsize)] | |
stepnr = 1 | |
def __init__(self,x,y): | |
self.grid[x][y] = self # put the Tile object in the grid array | |
self.x, self.y = x, y | |
# make a new object from the default cube: | |
obj = bpy.data.objects.new("Cube", bpy.data.meshes["Cube"]) | |
obj.location = (x*tile_size,y*tile_size,0) | |
obj.scale = [tile_size, tile_size, tile_size] | |
bpy.data.collections["Grid"].objects.link(obj) | |
self.obj = obj | |
self.age = 0 | |
self.nextlife = False | |
def get_neighbors(self): | |
x, y = self.x, self.y | |
l = x-1 | |
r = x+1 if x<gridsize-1 else 0 | |
d = y-1 | |
u = y+1 if y<gridsize-1 else 0 | |
g = self.grid | |
self.neighbors = [g[l][u], g[x][u], g[r][u], g[r][y], | |
g[r][d], g[x][d], g[l][d], g[l][y]] | |
def random_life(self): | |
if random() < .2: | |
self.nextlife = True | |
self.update() | |
def check(self): | |
sum = len([1 for n in self.neighbors if n.age > 0]) | |
if self.age >0 and (sum < 2 or sum > 3): | |
self.nextlife = False | |
elif sum == 3: | |
self.nextlife = True | |
def update(self): | |
if self.nextlife: | |
if self.age > 0: # staying alive | |
self.age += 1 | |
else: # is dead >> birth | |
self.age = 1 | |
# self.obj.location.z = log(self.age +1) * tile_size | |
self.obj.location.z = (1 - 1/(self.age+1) ) * tile_size * 2 | |
else: # it's dead | |
if self.age > 0: # it's alive but dies | |
self.age = 0 | |
else: # it stays dead | |
self.age -= 1 | |
# self.obj.location.z = -log(abs(self.age)+1) * tile_size | |
self.obj.location.z = (1 - 1/(abs(self.age)+1) ) * -tile_size * 2 | |
# add a keyframe | |
self.obj.keyframe_insert(data_path = "location", index = 2, frame = Tile.stepnr * 2) | |
# delete old tiles | |
for obj in bpy.data.collections["Grid"].objects: | |
bpy.data.collections["Grid"].objects.unlink(obj) | |
# initialize grid of tiles: | |
tiles = [Tile(x,y) for x in range(gridsize) for y in range(gridsize)] | |
for t in tiles: | |
t.random_life() | |
t.get_neighbors() | |
# main loop: | |
iterations = 300 | |
# set timeline length | |
bpy.context.scene.frame_end = time_stretch*iterations | |
for i in range(iterations): | |
for t in tiles: t.check() | |
for t in tiles: t.update() | |
Tile.stepnr += 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment