Skip to content

Commit

Permalink
add flip_x, flip_y, scale properties to Actor
Browse files Browse the repository at this point in the history
  • Loading branch information
yansnow78 committed Jan 28, 2022
1 parent 46a889f commit 1fe7b70
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 19 deletions.
94 changes: 75 additions & 19 deletions pgzero/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def calculate_anchor(value, dim, total):
MAX_ALPHA = 255 # Based on pygame's max alpha.


def transform_anchor(ax, ay, w, h, angle):
def transform_anchor(ax, ay, w, h, angle, scale=1.0):
"""Transform anchor based upon a rotation of a surface of size w x h."""
theta = -radians(angle)

Expand All @@ -68,8 +68,8 @@ def transform_anchor(ax, ay, w, h, angle):
ray = cax * sintheta + cay * costheta

return (
tw * 0.5 + rax,
th * 0.5 + ray
(tw * 0.5 + rax)*scale,
(th * 0.5 + ray)*scale
)


Expand All @@ -80,6 +80,22 @@ def _set_angle(actor, current_surface):
return pygame.transform.rotate(current_surface, actor._angle)


def _set_scale(actor, current_surface):
if actor._scale == 1.0:
# No changes required for default scale.
return current_surface
new_width = int(current_surface.get_width() * actor._scale)
new_height = int(current_surface.get_height() * actor._scale)
return pygame.transform.scale(current_surface, (new_width, new_height))


def _set_flip(actor, current_surface):
if (not actor._flip_x) and (not actor._flip_y):
# No changes required for default flip.
return current_surface
return pygame.transform.flip(current_surface, actor._flip_x, actor._flip_y)


def _set_opacity(actor, current_surface):
alpha = int(actor.opacity * MAX_ALPHA + 0.5) # +0.5 for rounding up.

Expand All @@ -104,8 +120,11 @@ class Actor:
a for a in dir(rect.ZRect) if not a.startswith("_")
]

function_order = [_set_opacity, _set_angle]
function_order = [_set_opacity, _set_scale, _set_flip, _set_angle]
_anchor = _anchor_value = (0, 0)
_scale = 1.0
_flip_x = False
_flip_y = False
_angle = 0.0
_opacity = 1.0

Expand Down Expand Up @@ -238,27 +257,62 @@ def _calc_anchor(self):
if self._angle == 0.0:
self._anchor = self._untransformed_anchor
else:
self._anchor = transform_anchor(ax, ay, ow, oh, self._angle)

@property
def angle(self):
return self._angle
self._anchor = transform_anchor(ax, ay, ow, oh, self._angle, self._scale)

@angle.setter
def angle(self, angle):
self._angle = angle
def _transform(self):
w, h = self._orig_surf.get_size()

ra = radians(angle)
ra = radians(self._angle)
sin_a = sin(ra)
cos_a = cos(ra)
self.height = abs(w * sin_a) + abs(h * cos_a)
self.width = abs(w * cos_a) + abs(h * sin_a)
self.height = int((abs(w * sin_a) + abs(h * cos_a))*self._scale)
self.width = int((abs(w * cos_a) + abs(h * sin_a))*self._scale)
ax, ay = self._untransformed_anchor
p = self.pos
self._anchor = transform_anchor(ax, ay, w, h, angle)
self._anchor = transform_anchor(ax, ay, w, h, self._angle, self._scale)
self.pos = p
self._update_transform(_set_angle)

@property
def angle(self):
return self._angle

@angle.setter
def angle(self, angle):
if self._angle != angle:
self._angle = angle
self._transform()
self._update_transform(_set_angle)

@property
def scale(self):
return self._scale

@scale.setter
def scale(self, scale):
if self._scale != scale:
self._scale = scale
self._transform()
self._update_transform(_set_scale)

@property
def flip_x(self):
return self._flip_x

@flip_x.setter
def flip_x(self, flip_x):
if self._flip_x != flip_x:
self._flip_x = flip_x
self._update_transform(_set_flip)

@property
def flip_y(self):
return self._flip_y

@flip_y.setter
def flip_y(self, flip_y):
if self._flip_y != flip_y:
self._flip_y = flip_y
self._update_transform(_set_flip)

@property
def opacity(self):
Expand All @@ -277,8 +331,10 @@ def opacity(self):
@opacity.setter
def opacity(self, opacity):
# Clamp the opacity to the allowable range.
self._opacity = min(1.0, max(0.0, opacity))
self._update_transform(_set_opacity)
new_opacity = min(1.0, max(0.0, opacity))
if self._opacity != new_opacity:
self._opacity = new_opacity
self._update_transform(_set_opacity)

@property
def pos(self):
Expand Down
21 changes: 21 additions & 0 deletions test/test_actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ def test_rotation(self):
a.angle += 1.0
self.assertEqual(a.pos, (100.0, 100.0))

def test_no_scaling(self):
a = Actor('alien', pos=(100.0, 100.0))
originial_size = (a.width, a.height)

a.scale = 1
self.assertEqual((a.width, a.height) + a.pos, originial_size + a.pos)

def test_scale_down(self):
a = Actor('alien', pos=(100.0, 100.0))
scale = 0.25
exp_size = (int(a.width*scale), int(a.height*scale))
a.scale = scale
self.assertEqual((a.width, a.height) + a.pos, exp_size + (100.0, 100.0))

def test_scale_up(self):
a = Actor('alien', pos=(100.0, 100.0))
scale = 2.5
exp_size = (int(a.width*scale), int(a.height*scale))
a.scale = scale
self.assertEqual((a.width, a.height) + a.pos, exp_size + (100.0, 100.0))

def test_opacity_default(self):
"""Ensure opacity is initially set to its default value."""
a = Actor('alien')
Expand Down

0 comments on commit 1fe7b70

Please sign in to comment.