I'm try to implement animation class via sfml.TransformableDrawable. In main script I wrote animation.position = (400, 400), but nothing happen with render position. I think that my implementation of draw method is wrong, but I don't know how make it right. Yes, documentation explains how drawable and transformable linked with each other, but it is still the dark forest for me.
Here my draw method implementation:
def draw (self, target, states):
# argument by reference -> states will be modified !!!
states.transform.combine(self.transformable.transform)
target.draw(self._sprite)
P.S.: sorry I'm accidentally added poll.
target.draw(self._sprite)
Should be
target.draw(self._sprite, states)
Yes, but in the C++ documentation:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
states passed by value, but in Python all arguments passed by reference and states must be saved.
But if I make copy of states it's don't work (just black window, without render):
def draw (self, target, states):
new_states = copy.copy(states)
new_states.transform.combine(self.transformable.transform)
target.draw(self._sprite, new_states)
By the way fixed version, also don't work, moreover after few frames program freeze and crash.:
def draw (self, target, states):
states.transform.combine(self.transformable.transform)
target.draw(self._sprite, states)
Here code of animation.py module:
import sfml as sf
class Animation(sf.TransformableDrawable):
_timer = sf.Clock()
def __init__ (self, sprite, duration):
sf.TransformableDrawable.__init__(self)
self._sprite = sprite
self._frame = 1
self._frames_count = sprite.texture.width // sprite.texture.height
self._frame_size = sprite.texture.height
self._sprite.texture_rectangle = sf.Rectangle((0, 0), (self._frame_size, self._frame_size))
self._rate = duration // self._frames_count
self.is_run = False
def start (self):
self._last_time = Animation._timer.elapsed_time.milliseconds
self._frame = 1
self.is_run = True
def stop (self):
self.is_run = False
def update (self):
if self.is_run:
# set number of renderable frame
current_time = Animation._timer.elapsed_time.milliseconds
elapsed_time = current_time - self._last_time
if elapsed_time >= self._rate:
offset = (elapsed_time // self._rate) % self._frames_count
self._frame = (self._frame + offset) % self._frames_count
self._last_time = current_time
# set renderable frame on sprte
frame_pos = (self._frame_size*self._frame-1, 0)
frame_size = (self._frame_size, self._frame_size)
self._sprite.texture_rectangle = sf.Rectangle(frame_pos, frame_size)
def draw (self, target, states):
states.transform.combine(self.transformable.transform)
target.draw(self._sprite, states)
Code of main script:
import sfml as sf
from animation import Animation
def main ():
wnd = sf.RenderWindow(sf.VideoMode(800, 800), "Anim test")
texture = sf.Texture.from_file("boxes.png")
sprite = sf.Sprite(texture)
animation = Animation(sprite, 1000)
animation.position = (400, 400)
animation.start()
while wnd.is_open:
for event in wnd.events:
if type(event) is sf.CloseEvent:
wnd.close()
wnd.clear(sf.Color.BLACK)
animation.update()
wnd.draw(animation)
wnd.display()
if __name__ == '__main__':
main()
I forgot to implement the __copy__ method of sf.RenderStates. Try a manual copy and tell me if it works:
def copy_renderstates(renderstates):
ret = sf.RenderStates()
ret.blend_mode = renderstates.blend_mode
ret.shader = renderstates.shader
ret.texture = renderstates.texture
ret.transform = renderstates.transform
return ret
Thanks for reporting this bug :)
Fix: both Laurent fixed draw method and draw method with manual copying, no longer produce a crash, but animation still drawn at left top corner.
Update: crashes don't occur only when I run script under IDLE.
Manual copying version:
def draw (self, target, states):
def copy_renderstates(renderstates):
ret = sf.RenderStates()
ret.blend_mode = renderstates.blend_mode
ret.shader = renderstates.shader
ret.texture = renderstates.texture
ret.transform = renderstates.transform
return ret
new_states = copy_renderstates(states)
new_states.transform.combine(self.transformable.transform)
target.draw(self._sprite, states)
Laurent fixed version:
def draw (self, target, states):
states.transform.combine(self.transformable.transform)
target.draw(self._sprite, states)
Update: I remade Animation class in sf.Transformable in an internal attribute style, and it's work, but looks ugly... Thus it's a bug most probably in the sf.TransformableDrawable.
Success! I was able to make Animation class which inherited from sfml.TransformableDrawable, and it work right! I use standart draw method, but states.transform.combine(self.transformable.transform) replacing states.transform.combine(self.transform):
def draw (self, target, states):
states.transform.combine(self.transform)
target.draw(self._sprite, states)