Skip to content

Commit

Permalink
Dithering
Browse files Browse the repository at this point in the history
  • Loading branch information
AlasdairWallaceMackie committed Nov 3, 2023
1 parent 92a9aab commit af084a0
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 11 deletions.
81 changes: 71 additions & 10 deletions bubble.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pyxel
from itertools import cycle
from copy import copy
from constants import BUBBLE_RADIUS_MIN, BUBBLE_RADIUS_MAX, BUBBLE_COLOR_CYCLE
from constants import BUBBLE_RADIUS_MIN, BUBBLE_RADIUS_MAX, BUBBLE_COLOR_CYCLE, BUBBLE_BORDER_COLOR, SCREENSAVER_BACKGROUND_COLOR

class Bubble:
def __init__(self, x, y, radius, index):
Expand All @@ -10,32 +9,36 @@ def __init__(self, x, y, radius, index):
self.radius = radius
self.index = index

self.BUBBLE_COLOR_CYCLE = copy(BUBBLE_COLOR_CYCLE)
self.color = self.init_color()
self.COLOR_CYCLE = copy(BUBBLE_COLOR_CYCLE)
self.current_color = self.init_color()
self.next_color = next(self.COLOR_CYCLE)
self.is_color_transitioning = False

self.visible = False

def update(self, instructions: [str]):
if instructions:
self.visible = True

self.update_color()
self.carry_out_instructions(instructions)

def draw(self):
if not self.visible:
return

self.draw_circle()
self.draw_highlight()
self.draw_border()
self.draw_dithering()
self.draw_highlight()

############################

def init_color(self):
""" Offsetting the color by the instance index ensures neighbors don't have the same color """
color = next(self.BUBBLE_COLOR_CYCLE)
color = next(self.COLOR_CYCLE)
for i in range(self.index):
color = next(self.BUBBLE_COLOR_CYCLE)
color = next(self.COLOR_CYCLE)

return color

Expand All @@ -47,7 +50,8 @@ def increment_radius(self, amount: int):
def carry_out_instructions(self, instructions: [str]):
for instruction in instructions:
match instruction:
case 'color': self.color = next(self.BUBBLE_COLOR_CYCLE)
case 'color':
self.is_color_transitioning = True
case 'bigger': self.increment_radius(1)
case 'smaller': self.increment_radius(-1)
case 'up': self.y -= 1
Expand All @@ -58,14 +62,22 @@ def carry_out_instructions(self, instructions: [str]):
case 'narrow': pass
case _: raise Exception(f'Invalid instruction: {instruction}')

def update_color(self):
if not self.is_color_transitioning:
return

self.current_color = self.next_color
self.next_color = next(self.COLOR_CYCLE)
self.is_color_transitioning = False

############################

def draw_circle(self):
pyxel.circ(
self.x,
self.y,
self.radius,
self.color,
self.current_color,
)

def draw_highlight(self):
Expand All @@ -78,4 +90,53 @@ def draw_highlight(self):
)

def draw_border(self):
pyxel.circb(self.x, self.y, self.radius + 1, pyxel.COLOR_NAVY)
pyxel.circb(self.x, self.y, self.radius + 1, BUBBLE_BORDER_COLOR)

######################
# Dithering Functions
######################

def draw_dithering(self):
if not self.is_color_transitioning:
return

try:
# We are offsetting the start point of the dithering algorithm. If it's initiated in the bubble's center, there will be an issue if the center is inside a neighbor bubble.
self.recursive_dither(
self.x + ((self.radius / 2) + 1),
self.y - ((self.radius / 2) + 1),
)
except:
# There is still a rare chance of a RecursionError, so we catch it here
return

def recursive_dither(self, x, y):
location_color = pyxel.pget(x, y)

if location_color in [BUBBLE_BORDER_COLOR, SCREENSAVER_BACKGROUND_COLOR]:
return

if location_color == self.current_color and not self.found_next_color_in_neighbor(x, y):
pyxel.pset(x, y, self.next_color)

self.color_neighbors(x, y)

def found_next_color_in_neighbor(self, x, y) -> bool:
for new_x, new_y in self.neighbor_coordinates(x, y):
if pyxel.pget(new_x, new_y) == self.next_color:
return True

return False

def color_neighbors(self, x, y):
for new_x, new_y in self.neighbor_coordinates(x, y):
if pyxel.pget(new_x, new_y) != self.next_color:
self.recursive_dither(new_x, new_y)

def neighbor_coordinates(self, x, y) -> [int, int]:
return [
(x + 1, y),
(x - 1, y),
(x, y + 1),
(x, y - 1),
]
1 change: 0 additions & 1 deletion bubble_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,3 @@ def translate_position(self, dx, dy):
for bubble in self.bubbles:
bubble.x += dx
bubble.y += dy

2 changes: 2 additions & 0 deletions constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
WINDOW_HEIGHT = WINDOW_WIDTH

SCREENSAVER_SPEED = 4 # Higher is slower
SCREENSAVER_BACKGROUND_COLOR = pyxel.COLOR_BLACK

BUBBLE_LINE_LENGTH = 32
BUBBLE_LINE_COUNT = 32
Expand All @@ -14,6 +15,7 @@
BUBBLE_SPACING_MAX = 14
BUBBLE_RADIUS_MIN = 5
BUBBLE_RADIUS_MAX = 8
BUBBLE_BORDER_COLOR = pyxel.COLOR_NAVY

SCREENSAVER_ORIGIN_X = -2
SCREENSAVER_ORIGIN_Y = -32
Expand Down

0 comments on commit af084a0

Please sign in to comment.