-
Notifications
You must be signed in to change notification settings - Fork 41
Rounded Rectangle Shape
In order to create Custom Shape Types in SFML, it is recommended to subclass the abstract class Shape
and reimplement some methods. Due to porting difficulties, this does not seem possible in python-sfml.
However, the class sf.ConvexShape
basically provides the same capabilities, but in a different format, without the need to subclass anything. But it is not as convenient, mainly because you can't simply make your own class out of it.
That's why I made a class CustomShape
(which is actually an sf.TransformableDrawable
) that contains and manages a sf.ConvexShape
and lets you subclass it to implement the function points
that should simply return a list of points. You also need to call update
whenever the points change, and the points
function will be called automatically. What's very important, you can use such a class exactly like you would use any sf.Shape
, because the attributes that sf.ConvexShape
exposes, e.g. outline_thickness
or rotation
are retranslated from the class.
Here is an example of how to use it, inspired by "Draw rounded rectangles".
You're free to do whatever you want with the code below.
It works with Python 3.x and should work with Python 2.7
class RoundedRectangleShape(CustomShape):
def __init__(self, size, radius, corner_points=5):
CustomShape.__init__(self)
self._radius = radius
self._corner_points = corner_points
self.size = size
def points(self):
points = []
centers = [
(self.size.x-self.radius, self.radius), (self.radius, self.radius),
(self.radius, self.size.y-self.radius), (self.size.x-self.radius, self.size.y-self.radius)
]
for index in range(self.corner_points*4):
center_index = index//self.corner_points
angle = (index-center_index)*math.pi/2/(self.corner_points-1);
center = centers[center_index]
points.append((center[0]+self.radius*math.cos(angle), center[1]-self.radius*math.sin(angle)))
return points
@property
def size(self):
return self._size
@size.setter
def size(self, value):
self._size = sf.Vector2(*value)
self.update()
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
self._radius = value
self.update()
@property
def corner_points(self):
return self._corner_points
@corner_points.setter
def corner_points(self, value):
self._corner_points = value
self.update()
The needed imports are: sfml as sf
and math
.
And here is the CustomShape
"abstract" class itself:
class CustomShape(sf.TransformableDrawable):
_retranslated_names = {name for name in dir(sf.ConvexShape) if not name.startswith('_')}
def __init__(self):
self._shape = sf.ConvexShape()
def points(self):
raise NotImplementedError("Abstract method")
def update(self):
pts = self.points()
self._shape.point_count = len(pts)
for i, p in enumerate(pts):
self._shape.set_point(i, p)
def draw(self, target, states):
states.transform *= self.transform
target.draw(self._shape, states)
def __setattr__(self, name, value):
if name in CustomShape._retranslated_names:
setattr(self._shape, name, value)
else:
object.__setattr__(self, name, value)
def __getattr__(self, name):
return getattr(self._shape, name)
shape = RoundedRectangleShape((80, 50), 10, corner_points=8)
shape.position = (200, 300)
shape.fill_color = sf.Color.GREEN
target.draw(shape)