Help with SpriteNode movement using buttons
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.
- 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:
- 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).
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/1, 0, 2, TIMING_SINODIAL) left_move = Action.move_by(self.size/-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())
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.
@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.
pressedto True or False in their
touch_endedmethods. Then you can just check e.g.
You gentlemen are brilliant! Thank you so much, this is exactly what I needed to move forward with this little project.