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.


    Help with SpriteNode movement using buttons

    Pythonista
    3
    4
    2454
    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.
    • KnightExcalibur
      KnightExcalibur last edited by KnightExcalibur

      It was difficult for me to figure out because I'm a beginner, but I seem to have gotten the sprite movement halfway working with buttons. The rotation of the walking textures works with the gravity() module,
      (see: https://github.com/bbroadhead/pythonista-rpg/blob/master/knight_test.py or part 3 of the pythonista game tutorial)
      but it is a little wonky with using the buttons to move. I think it’s just because I haven’t figured out how to get update(self) to update only while the sprite is in motion. In the game tutorial, it uses a simple threshold for gravity() so it only updates when the accelerometer reads above a certain value, but I’m unsure what to reference in update(self) so it only updates when you’re pressing a button. I tried to reference touch_began but no matter how I tried it didn’t like that.

      1. What could I put in the spot that I commented out so update(self) recognizes touch_began?

      My end goal is to make the sprite four directional like an RPG instead of side-scrolling. Reference this video for an example.
      Which brings me to my second question:
      2. How would I make the sprite move a static distance while you’re holding down the button? (For example, move a certain number of pixels across the screen) rather than movement that references a fraction of the screen size as used below (I implemented the idea from this thread, but I want the sprite to move independently of screen size).

      I used a resized version of this sprite (but the sprite can easily be changed back to the alien from the original example),
      and this song (you can comment out the Player).

      Thank you in advance for your help!

      import ui
      from scene import *
      import sound
      
      standing_texture = Texture('Idle.png',)
      walk_textures = [Texture('Walk 1.png'), Texture('Walk 2.png'), Texture('Walk 3.png'), 
      									Texture('Walk 4.png'), Texture('Walk 5.png'), Texture('Walk 6.png'), 
      									Texture('Walk 7.png'), Texture('Walk 8.png'), Texture('Walk 9.png'), 
      									Texture('Walk 10.png')]
      player = sound.Player('battleThemeA.mp3')
      player.number_of_loops = -1
      
      class MyScene(Scene):
      	def setup(self):
      		self.background_color = '#7bc7ff'
      		ground = Node(parent=self)
      		x = 0
      		while x <= self.size.w + 64:
      			tile = SpriteNode('plf:Ground_Grass', position=(x, 0))
      			ground.add_child(tile)
      			x += 64
      		self.player = SpriteNode(standing_texture)
      		self.player.anchor_point = (0.5, 0)
      		self.player.position = (self.size.w/2, 20)
      		self.add_child(self.player)
      		self.right_button = ShapeNode(ui.Path.rounded_rect(0, 0, 100, 50, 20),
      														position=(250, 100),
      														fill_color='black',
      														parent=self)
      		self.left_button = ShapeNode(ui.Path.rounded_rect(0, 0, 100, 50, 20),
      														position=(100, 100),
      														fill_color='black',
      														parent=self)
      		self.walk_step = -1
      		player.play()
      
      	def touch_began(self, touch):
      		right_move = Action.move_by(self.size[0]/1, 0, 2, TIMING_SINODIAL)
      		left_move = Action.move_by(self.size[0]/-1, 0, 2, TIMING_SINODIAL)
      		if touch.location in self.right_button.frame:
      			self.player.run_action(right_move, 'move_action_key')
      			Action.repeat(right_move, 0)
      			self.player.x_scale = 1
      			moving += 1
      		elif touch.location in self.left_button.frame:
      			self.player.run_action(left_move, 'move_action_key')
      			Action.repeat(left_move, 0)
      			self.player.x_scale = -1	
      
      	def touch_ended(self, touch):
      		if touch.location in self.right_button.frame:
      			self.player.remove_action('move_action_key')
      		elif touch.location in self.left_button.frame:
      			self.player.remove_action('move_action_key')
      
      	def stop(self):
      		player.stop()
      
      	def update(self):
      		#if moving: -------------------------------what to do here?
      			x = self.player.position.x
      			x = max(0, min(self.size.w, x))
      			self.player.position = (x, 20)
      			step = int(self.player.position.x / 20) % 10
      			if step != self.walk_step:
      				self.player.texture = walk_textures[step]
      				sound.play_effect('rpg:Footstep00', 0.05, 1.0 + 0.5 * step)
      				self.walk_step = step
      		else:
      			self.player.texture = standing_texture
      			self.walk_step = -1
      			
      run(MyScene())
      
      mikael 1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by

        here is a very simple example using the built in exAmple:

        	def touch_began(self,touch):
        		if touch.location.x>.7*self.size.w:
        			self.x_move_dir=+1
        		if touch.location.x < .3*self.size.w:
        			self.x_move_dir=-1
        	def touch_ended(self,touch):
        			self.x_move_dir=0
        

        then, you replace g.x in update_player with self.x_move_dir.
        you could have a similar logic for y motion.

        of course, this method doesnt work for multiple fingers. for that you need to keep a dictionary of touches, that gets set in touch_began (use touch.id as the key). you update the touch in touch_moved, and delete it in touch_ended. then, in your update function, you have to cycle through the active touches to see what is currently being pressed each cycle.

        1 Reply Last reply Reply Quote 0
        • mikael
          mikael @KnightExcalibur last edited by

          @KnightExcalibur, if you have many buttons, it is probably clearer to add custom ui views with scene.view.add_subview. They can set e.g. pressed to True or False in their touch_began and touch_ended methods. Then you can just check e.g. if up_button.pressed:

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

            You gentlemen are brilliant! Thank you so much, this is exactly what I needed to move forward with this little project.

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