From 37343739e859f9ec3963faa59fe3dcfb91f97710 Mon Sep 17 00:00:00 2001 From: James Turk Date: Tue, 23 Apr 2024 21:26:34 -0500 Subject: [PATCH] most things working, not text, draw_engine interface still fluid --- src/doodles/doodles.py | 4 ++-- src/doodles/draw_engine.py | 17 +++++++++++++++++ src/doodles/lines.py | 5 +++-- src/doodles/shapes.py | 20 ++++++++++---------- src/doodles/world.py | 24 +++++++++++++++++++++++- 5 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 src/doodles/draw_engine.py diff --git a/src/doodles/doodles.py b/src/doodles/doodles.py index 3bef6f5..060d3ac 100644 --- a/src/doodles/doodles.py +++ b/src/doodles/doodles.py @@ -46,7 +46,7 @@ class Doodle(ABC): world.add(self) @abstractmethod - def draw(self, screen) -> None: + def draw(self) -> None: """ All doodles need to be drawable, but there is no way we can provide an implementation without @@ -231,7 +231,7 @@ class Group(Doodle): def __repr__(self): return f"Group(pos={self.world_vec}, doodles={len(self._doodles)})" - def draw(self, screen): + def draw(self): """ Groups, despite being an abstract concept, are drawable. To draw a group is to draw everything in it. diff --git a/src/doodles/draw_engine.py b/src/doodles/draw_engine.py new file mode 100644 index 0000000..a362f3f --- /dev/null +++ b/src/doodles/draw_engine.py @@ -0,0 +1,17 @@ +import abc + + +class DrawEngine(abc.ABC): + @abc.abstractmethod + def circle_draw(self, screen): + pass + + @abc.abstractmethod + def rect_draw(self, screen): + pass + + @abc.abstractmethod + def line_draw(self, screen): + pass + + diff --git a/src/doodles/lines.py b/src/doodles/lines.py index a4b3201..8df0f96 100644 --- a/src/doodles/lines.py +++ b/src/doodles/lines.py @@ -3,6 +3,7 @@ import random import pygame from typing import Callable from .doodles import Doodle +from .world import world class Line(Doodle): @@ -22,7 +23,7 @@ class Line(Doodle): def __repr__(self): return f"Line(pos={self.world_vec}, end={self.end_vec}, {self._color})" - def draw(self, screen): + def draw(self): """ Implementation of the abstract draw function for the line. @@ -41,7 +42,7 @@ class Line(Doodle): to the class and gaining flexibility from separating presentation logic from data manipulation. """ - pygame.draw.aaline(screen, self._color, self.world_vec, self.end_vec) + world.draw_engine.line_draw(self) def to(self, x: float, y: float) -> "Doodle": """ diff --git a/src/doodles/shapes.py b/src/doodles/shapes.py index 84dbe55..8cdae99 100644 --- a/src/doodles/shapes.py +++ b/src/doodles/shapes.py @@ -1,6 +1,7 @@ import random import pygame from .doodles import Doodle +from .world import world class Circle(Doodle): @@ -15,8 +16,9 @@ class Circle(Doodle): def __repr__(self): return f"Circle(pos={self.world_vec}, radius={self._radius}, {self._color}, parent={self._parent}))" - def draw(self, screen): - pygame.draw.circle(screen, self.rgba, self.world_vec, self._radius) + def draw(self): + # TODO: do we need to override draw? can we move this to Doodle.draw + world.draw_engine.circle_draw(self) def radius(self, r: float) -> "Doodle": """ @@ -25,6 +27,10 @@ class Circle(Doodle): self._radius = r return self + @property + def radius_val(self) -> float: + return self._radius + def grow(self, by: float): """ Modify radius by an amount. (Negative to shrink.) @@ -50,14 +56,8 @@ class Rectangle(Doodle): def __repr__(self): return f"Rect(pos={self.world_vec}, width={self._width}, height={self._height}, parent={self._parent})" - def draw(self, screen): - rect = pygame.Rect( - self.world_x - self._width / 2, - self.world_y - self._height / 2, - self._width, - self._height, - ) - pygame.draw.rect(screen, self._color, rect) + def draw(self): + world.draw_engine.rect_draw(self) def width(self, w: float) -> "Doodle": """ diff --git a/src/doodles/world.py b/src/doodles/world.py index b791fff..9a10f57 100644 --- a/src/doodles/world.py +++ b/src/doodles/world.py @@ -1,5 +1,26 @@ from .color import Color import pygame +# TODO: fix this with a dynamic load +from .draw_engine import DrawEngine + + +class PygameDrawEngine(DrawEngine): + def circle_draw(self, c: "Circle"): + pygame.draw.circle(world.buffer, c.rgba, c.world_vec, c.radius_val) + + def rect_draw(self, r: "Rectangle"): + # TODO: make accessors + rect = pygame.Rect( + r.world_x - r._width / 2, + r.world_y - r._height / 2, + r._width, + r._height, + ) + pygame.draw.rect(world.buffer, r.rgba, rect) + + def line_draw(self, ll: "Line"): + print("line_draw", ll) + pygame.draw.aaline(world.buffer, ll.rgba, ll.world_vec, ll.end_vec) class World: @@ -48,6 +69,7 @@ class World: self._drawables = [] self.background_color = Color.WHITE self.screen = None + self.draw_engine = PygameDrawEngine() def init(self): """ @@ -85,7 +107,7 @@ class World: # rendering self.buffer.fill((*self.background_color, 255)) for d in sorted(self._drawables, key=lambda d: d._z_index): - d.draw(self.buffer) + d.draw() self.screen.blit(self.buffer, (0, 0)) pygame.display.flip()