def render(self, out): # Spontaneous birth: Rare after startup if (len(self._dragons) < self.parameter('pop-limit').get() ) and random.random() < self.parameter('birth-rate').get(): strand = random.randint(0, BufferUtils.num_strands - 1) fixture = random.randint( 0, BufferUtils.strand_num_fixtures(strand) - 1) address = BufferUtils.logical_to_index((strand, fixture, 0)) if address not in [d.loc for d in self._dragons]: self._dragons.add(_Dragon(self, address, 1, self._current_time)) # Dragon life cycle to_add = set() to_remove = set() population = len(self._dragons) for dragon in self._dragons: population += dragon.render(to_add, to_remove, population) self._dragons = (self._dragons | to_add) - to_remove # Draw tails tails_to_remove = [] for loc, time, fader in self._tails: if (self._current_time - time) > self.parameter('tail-persist').get(): if (loc, time, fader) in self._tails: tails_to_remove.append((loc, time, fader)) self.setPixelHLS(self._buffer, loc, (0, 0, 0)) else: progress = (self._current_time - time) / self.parameter('tail-persist').get() self.setPixelHLS(self._buffer, loc, fader.get_color(progress * self._fader_steps)) for tail in tails_to_remove: self._tails.remove(tail) np.copyto(out, self._buffer)
def draw(self, dt): self._current_time += dt self._mass_destruction_countdown -= dt # Ensure that empty displays start up with some seeds p_birth = (1.0 - self._spontaneous_birth_probability) if self._population > 5 else 0.5 # Spontaneous birth: Rare after startup if (self._population < self._population_limit) and random.random() + self.parameter('audio-onset-birth-boost').get() > p_birth: strand = random.randint(0, BufferUtils.num_strands - 1) fixture = random.randint(0, BufferUtils.strand_num_fixtures(strand) - 1) pixel = random.randint(0, BufferUtils.fixture_length(strand, fixture) - 1) address = BufferUtils.logical_to_index((strand, fixture, pixel)) if address not in (self._growing + self._alive + self._dying + self._fading_out): self._growing.append(address) self._time[address] = self._current_time self._population += 1 self._spread_boost *= self.parameter('audio-onset-spread-boost-echo').get() if self._mixer.is_onset(): self._spread_boost += self.parameter('audio-onset-spread-boost').get() # Color growth for address in self._growing: neighbors = self.scene().get_pixel_neighbors(address) p, color = self._get_next_color(address, self._growth_time, self._current_time) if p >= 1.0: self._growing.remove(address) self._alive.append(address) self._time[address] = self._current_time self.setPixelHLS(address, color) # Spread spread_rate = self._spread_rate + self._spread_boost if (self._population < self._population_limit) and (random.random() < spread_rate * dt): for spread in neighbors: if spread not in (self._growing + self._alive + self._dying + self._fading_out): self._growing.append(spread) self._time[spread] = self._current_time self._population += 1 # Lifetime for address in self._alive: neighbors = self.scene().get_pixel_neighbors(address) live_neighbors = [i for i in neighbors if i in self._alive] lt = self._life_time if len(neighbors) < 2: lt = self._isolated_life_time if len(live_neighbors) < 3 and ((self._current_time - self._time[address]) / lt) >= 1.0: self._alive.remove(address) self._dying.append(address) self._time[address] = self._current_time self._population -= 1 self.setPixelHLS(address, self._alive_color) # Spread if (self._population < self._population_limit) and random.random() < self._birth_rate * dt: for spread in neighbors: if spread not in (self._growing + self._alive + self._dying + self._fading_out): self._growing.append(spread) self._time[spread] = self._current_time self._population += 1 # Color decay for address in self._dying: p, color = self._get_next_color(address, self._death_time, self._current_time + self.parameter('audio-onset-death-boost').get()) if p >= 1.0: self._dying.remove(address) self._fading_out.append(address) self._time[address] = self._current_time self.setPixelHLS(address, color) # Fade out for address in self._fading_out: p, color = self._get_next_color(address, self._fade_out_time, self._current_time + self.parameter('audio-onset-death-boost').get()) if p >= 1.0: self._fading_out.remove(address) self.setPixelHLS(address, color) # Mass destruction if (self._population == self._population_limit) or \ (self._population > self._mass_destruction_threshold and self._mass_destruction_countdown <= 0): for i in self._alive: if random.random() > 0.95: self._alive.remove(i) self._dying.append(i) self._population -= 1 for i in self._growing: if random.random() > 0.85: self._growing.remove(i) self._dying.append(i) self._population -= 1 self._mass_destruction_countdown = self.parameter('mass-destruction-time').get()
def draw(self, dt): self._current_time += dt # Spontaneous birth: Rare after startup if (len(self._dragons) < self.parameter('pop-limit').get()) and random.random() < self.parameter('birth-rate').get(): strand = random.randint(0, BufferUtils.num_strands - 1) fixture = random.randint(0, BufferUtils.strand_num_fixtures(strand) - 1) address = BufferUtils.logical_to_index((strand, fixture, 0)) if address not in [d.loc for d in self._dragons]: self._dragons.append(self.Dragon(address, 1, self._current_time)) growth_rate = self.parameter('growth-rate').get() # Dragon life cycle for dragon in self._dragons: # Fade in if dragon.growing: p = (self._current_time - dragon.lifetime) / self.parameter('growth-time').get() if (p > 1): p = 1.0 color = self._growth_fader.get_color(p * self._fader_steps) if p >= 1.0: dragon.growing = False dragon.alive = True dragon.lifetime = self._current_time self.setPixelHLS(dragon.loc, color) # Alive - can move or die if dragon.alive: dragon.growth += dt * growth_rate for times in range(int(dragon.growth)): s, f, p = BufferUtils.index_to_logical(dragon.loc) self.setPixelHLS(dragon.loc, (0, 0, 0)) if random.random() < dragon.growth: dragon.growth -= 1 # At a vertex: optionally spawn new dragons if dragon.moving and (p == 0 or p == (self.scene().fixture(s, f).pixels - 1)): neighbors = self.scene().get_pixel_neighbors(dragon.loc) neighbors = [BufferUtils.index_to_logical(n) for n in neighbors] random.shuffle(neighbors) # Kill dragons that reach the end of a fixture dragon.moving = False if dragon in self._dragons: self._dragons.remove(dragon) # Iterate over candidate pixels that aren't on the current fixture num_children = 0 for candidate in [n for n in neighbors if n[1] != f]: child_index = BufferUtils.logical_to_index(candidate) if num_children == 0: # Spawn at least one new dragon to replace the old one. This first one skips the growth. dir = 1 if candidate[2] == 0 else -1 child = self.Dragon(child_index, dir, self._current_time) child.growing = False child.alive = True child.moving = False self._dragons.append(child) num_children += 1 elif (len(self._dragons) < self.parameter('pop-limit').get()): # Randomly spawn new dragons if random.random() < self.parameter('birth-rate').get(): dir = 1 if candidate[2] == 0 else -1 child = self.Dragon(child_index, dir, self._current_time) child.moving = False self._dragons.append(child) num_children += 1 break; else: # Move dragons along the fixture self._tails.append((dragon.loc, self._current_time, self._tail_fader)) new_address = BufferUtils.logical_to_index((s, f, p + dragon.dir)) dragon.loc = new_address dragon.moving = True self.setPixelHLS(new_address, self._alive_color) # Kill dragons that run into each other if dragon in self._dragons: colliding = [d for d in self._dragons if d != dragon and d.loc == dragon.loc] if len(colliding) > 0: #print "collision between", dragon, "and", colliding[0] self._dragons.remove(dragon) self._dragons.remove(colliding[0]) self._tails.append((dragon.loc, self._current_time, self._explode_fader)) neighbors = self.scene().get_pixel_neighbors(dragon.loc) for neighbor in neighbors: self._tails.append((neighbor, self._current_time, self._explode_fader)) break # Draw tails for loc, time, fader in self._tails: if (self._current_time - time) > self.parameter('tail-persist').get(): if (loc, time, fader) in self._tails: self._tails.remove((loc, time, fader)) self.setPixelHLS(loc, (0, 0, 0)) else: progress = (self._current_time - time) / self.parameter('tail-persist').get() self.setPixelHLS(loc, fader.get_color(progress * self._fader_steps))
def draw(self, dt): self._current_time += dt self._mass_destruction_countdown -= dt # Ensure that empty displays start up with some seeds p_birth = (1.0 - self._spontaneous_birth_probability ) if self._population > 5 else 0.5 # Spontaneous birth: Rare after startup if (self._population < self._population_limit) and random.random( ) + self.parameter('audio-onset-birth-boost').get() > p_birth: strand = random.randint(0, BufferUtils.num_strands - 1) fixture = random.randint( 0, BufferUtils.strand_num_fixtures(strand) - 1) pixel = random.randint( 0, BufferUtils.fixture_length(strand, fixture) - 1) address = BufferUtils.logical_to_index((strand, fixture, pixel)) if address not in (self._growing + self._alive + self._dying + self._fading_out): self._growing.append(address) self._time[address] = self._current_time self._population += 1 self._spread_boost *= self.parameter( 'audio-onset-spread-boost-echo').get() if self._mixer.is_onset(): self._spread_boost += self.parameter( 'audio-onset-spread-boost').get() # Color growth for address in self._growing: neighbors = self.scene().get_pixel_neighbors(address) p, color = self._get_next_color(address, self._growth_time, self._current_time) if p >= 1.0: self._growing.remove(address) self._alive.append(address) self._time[address] = self._current_time self.setPixelHLS(address, color) # Spread spread_rate = self._spread_rate + self._spread_boost if (self._population < self._population_limit) and ( random.random() < spread_rate * dt): for spread in neighbors: if spread not in (self._growing + self._alive + self._dying + self._fading_out): self._growing.append(spread) self._time[spread] = self._current_time self._population += 1 # Lifetime for address in self._alive: neighbors = self.scene().get_pixel_neighbors(address) live_neighbors = [i for i in neighbors if i in self._alive] lt = self._life_time if len(neighbors) < 2: lt = self._isolated_life_time if len(live_neighbors) < 3 and ( (self._current_time - self._time[address]) / lt) >= 1.0: self._alive.remove(address) self._dying.append(address) self._time[address] = self._current_time self._population -= 1 self.setPixelHLS(address, self._alive_color) # Spread if (self._population < self._population_limit ) and random.random() < self._birth_rate * dt: for spread in neighbors: if spread not in (self._growing + self._alive + self._dying + self._fading_out): self._growing.append(spread) self._time[spread] = self._current_time self._population += 1 # Color decay for address in self._dying: p, color = self._get_next_color( address, self._death_time, self._current_time + self.parameter('audio-onset-death-boost').get()) if p >= 1.0: self._dying.remove(address) self._fading_out.append(address) self._time[address] = self._current_time self.setPixelHLS(address, color) # Fade out for address in self._fading_out: p, color = self._get_next_color( address, self._fade_out_time, self._current_time + self.parameter('audio-onset-death-boost').get()) if p >= 1.0: self._fading_out.remove(address) self.setPixelHLS(address, color) # Mass destruction if (self._population == self._population_limit) or \ (self._population > self._mass_destruction_threshold and self._mass_destruction_countdown <= 0): for i in self._alive: if random.random() > 0.95: self._alive.remove(i) self._dying.append(i) self._population -= 1 for i in self._growing: if random.random() > 0.85: self._growing.remove(i) self._dying.append(i) self._population -= 1 self._mass_destruction_countdown = self.parameter( 'mass-destruction-time').get()