omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    LabelSprite rotate_by problem

    Pythonista
    problem sprite rotation
    4
    13
    8329
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • amdescombes
      amdescombes last edited by

      Hello everyone,

      Newbie question : I am trying to create an animation of a label moving like a pendulum. I tried using a SpriteLabel rotating around an arbitrary point using Action.rotate_by, but it always rotates around the lower left corner of the screen (0, 0) and not around the top center, is there any way around this ?
      Here is the exact code I am using:

      from scene import *
      from math import *
      
      class MyScene(Scene):
      
      	def setup(self):
      		self.background_color = 'black'
      		self.anchor_point = (0.5, 0.0)
      		self.timelabel = LabelNode(position=self.size / 2, text='time')
      		self.add_child(self.timelabel)
      		self.timelabel.rotation = -pi / 8.0
      		self.run_action(Action.repeat(Action.sequence(Action.rotate_by(pi / 4.0, 1, TIMING_EASE_IN_OUT), Action.rotate_by(-pi / 4.0, 1, TIMING_EASE_IN_OUT), 0), 0))
      
      run(MyScene(), PORTRAIT)
      

      Cheers
      Andre

      1 Reply Last reply Reply Quote 0
      • omz
        omz last edited by omz

        Is this close to the behavior you want?

        from scene import *
        from math import *
        
        class MyScene(Scene):
        
        	def setup(self):
        		self.background_color = 'black'
        		self.time_anchor = Node(position=(self.size.w/2, 0), parent=self)
        		self.timelabel = LabelNode(position=(0, self.size.h/2), text='time')
        		self.time_anchor.add_child(self.timelabel)
        		rotate_action = Action.repeat(Action.sequence(Action.rotate_to(pi / 4.0, 1, TIMING_EASE_IN_OUT), Action.rotate_to(-pi / 4.0, 1, TIMING_EASE_IN_OUT), 0), 0)
        		self.time_anchor.run_action(rotate_action)
        		
        run(MyScene(), PORTRAIT)
        

        Things I've changed:

        • Added time_label to a container Node (time_anchor), so it can be rotated around an arbitrary point without rotating the whole scene (your approach of rotating the scene itself becomes problematic when you want to add more things to the scene; also, the anchor_point attribute is ignored for scenes)
        • Changed rotate_by to rotate_to -- this is just a guess, but I think the resulting effect may be closer to what you're after.
        amdescombes 1 Reply Last reply Reply Quote 1
        • amdescombes
          amdescombes last edited by

          That is exactly what I wanted omz, thanks alot!

          Cheers
          Andre

          1 Reply Last reply Reply Quote 0
          • amdescombes
            amdescombes @omz last edited by

            Hi @omz,

            is there a way to include a dynamic variable in an Action?

            I was thinking of using the variable self.angle in the Action like this:

            from itertools import cycle
            from scene import *
            from math import *
            
            class MyScene(Scene):
            
                def setup(self):
                    self.background_color = 'black'
                    self.time_anchor = Node(position=(self.size.w/2, 0), parent=self)
                    self.timelabel = LabelNode(position=(0, self.size.h/2), text='time')
                    self.time_anchor.add_child(self.timelabel)
                    self.angles = cycle([pi/4, -pi/4])
                    rotate_action = Action.repeat(Action.rotate_to(self.angles.next(), 1, TIMING_EASE_IN_OUT), 0)
                    self.time_anchor.run_action(rotate_action)
            
            run(MyScene(), PORTRAIT)
            

            This does not seem to work it stays at the same angle all the time, is there any way around it?
            Thanks in advance.

            Cheers
            Andre

            1 Reply Last reply Reply Quote 0
            • abcabc
              abcabc last edited by

              One way to do is to write your own 'Action.repeat".. In the following code, the angles get changed when you touch. May be others could suggest better ways to this.

              from scene import *
              from math import *
              
              class MyScene(Scene):
                  def repeat(self):
                      self.rotate_action = Action.sequence(
                          Action.rotate_to(self.angles[0], 1, TIMING_EASE_IN_OUT),
                          Action.rotate_to(self.angles[1], 1, TIMING_EASE_IN_OUT), 
                          Action.call(self.repeat), 0)
                      self.time_anchor.run_action(self.rotate_action)    
              
                  def setup(self):
                      self.background_color = 'black'
                      self.time_anchor = Node(position=(self.size.w/2, 0), parent=self)
                      self.timelabel = LabelNode(position=(0, self.size.h/2), text='time')
                      self.time_anchor.add_child(self.timelabel)
                      self.angles = (pi/8, -pi/8)
                      self.rotate_action = Action.sequence(
                          Action.rotate_to(self.angles[0], 1, TIMING_EASE_IN_OUT),
                          Action.rotate_to(self.angles[1], 1, TIMING_EASE_IN_OUT), 
                          Action.call(self.repeat), 0)
                      self.time_anchor.run_action(self.rotate_action)
                      self.toggle = True
                      
                  def touch_began(self, touch):
                      if self.toggle:
                          self.angles = (pi/4, -pi/4)
                      else:
                          self.angles = (pi/8, -pi/8)
                      self.toggle = not self.toggle
                      
              run(MyScene(), PORTRAIT)
              
              
              
              
              amdescombes 1 Reply Last reply Reply Quote 1
              • cvp
                cvp last edited by cvp

                Try this code, you can easily define the fps (frame per second), you work in degrees and you can define min/max, and you can have more interaction than with run_action:

                from scene import *
                from math import *
                
                class MyScene(Scene):
                	def setup(self):
                		self.background_color = 'black'
                		self.timelabel = LabelNode(position=self.size/2, text='time')
                		self.add_child(self.timelabel)
                		self.ang = -45
                		self.delta = 1
                	def update(self):
                		self.ang = self.ang + self.delta
                		if abs(self.ang) > 45:
                			self.delta = -self.delta
                			self.ang = self.ang + self.delta
                		self.timelabel.rotation = math.radians(self.ang)
                		r = self.size[1]/2
                		x = self.size[0]/2+r*sin(math.radians(-self.ang))
                		y = r*cos(math.radians(self.ang))
                		self.timelabel.position = (x,y)
                
                run(MyScene(), PORTRAIT,frame_interval=1)
                
                amdescombes 1 Reply Last reply Reply Quote 1
                • abcabc
                  abcabc last edited by

                  You can change the first line of the update function to the following code if you want TIMING_EASE_IN_OUT like effect

                  self.ang = self.ang + self.delta*cos(radians(2*self.ang)) +.05*self.delta
                  

                  Note that it assumes the maximum angle is 45. If it is different, you need to change 2*self.ang to appropriate expression.

                  1 Reply Last reply Reply Quote 1
                  • amdescombes
                    amdescombes @abcabc last edited by

                    Thank you @abcabc,
                    creating a new action is great, do I need to do a self.time_anchor.remove_all_actions ()before?
                    Cheers
                    Andre

                    1 Reply Last reply Reply Quote 0
                    • amdescombes
                      amdescombes @cvp last edited by

                      Thanks @cvp,

                      I was trying to learn automatic actions so I had not considered your approach, I guess I was being lazy :-)

                      Cheers
                      Andre

                      1 Reply Last reply Reply Quote 0
                      • cvp
                        cvp last edited by cvp

                        No problem, I had never used scene thus I'm always happy to try and thus to learn something. Good luck

                        1 Reply Last reply Reply Quote 0
                        • abcabc
                          abcabc last edited by

                          I think that it is not needed since the previous action will be complete by that time. I assume that "run_action" call spawns a thread and
                          the Action.call does not wait for the thread to complete and it returns immediately. I hope that run_action call overheads are not much.I do not know the internal implementation details and may be omz can answer this.

                          1 Reply Last reply Reply Quote 1
                          • abcabc
                            abcabc last edited by

                            "run_action" may not be spawning a thread and it may just create action related data structures. which will be updated every frame. Anyway other experts ( I am just learning) could help you on this.

                            1 Reply Last reply Reply Quote 0
                            • amdescombes
                              amdescombes last edited by

                              Well, it's running just fine!
                              Thanks to all!
                              Cheers
                              Andre

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post
                              Powered by NodeBB Forums | Contributors