Forum Archive

Scene module touch controls

lachlantula

Hi all,
my friend and I are working on a little game together, making use of the Scene module. However we've found that the tilt controls aren't very intuitive for what we're aiming to make, but we're kind of clueless on how to make buttons or similar. One idea was to make a sprite that detects when it's pressed by checking if the touch was within a certain range, but there's probably a more elegant way of doing this.

Thanks :)

lachlantula

It's definitely not the best solution, but using halves of the screen for moving left and right does work well enough for now.

def touch_began(self, touch):
    x, y = touch.location
    self.a = x
    if self.a <= 500:
        self.b = 'moveright'
    else:
        self.b = 'moveleft'
    self.update_player(True)    

def update_player(self, touch):
    x = self.player.position.x
    if touch == True:
        x += 32
        y = 32
        if self.b == 'moveleft':
            move_action = Action.move_to(x+32, y, 0.01)
            self.player.run_action(move_action)
        else:
            move_action = Action.move_to(x-64, y, 0.01)
            self.player.run_action(move_action)

If anyone has any ideas on how to improve that code suggestions are very welcome :)

abcabc

May be try the following.

import scene, ui

class ButtonNode (scene.SpriteNode):
    def __init__(self, title, *args, **kwargs):
        scene.SpriteNode.__init__(self, 'pzl:Button1', *args, **kwargs)        
        button_font = ('Avenir Next', 20)
        font_color = 'black'
        self.title_label = scene.LabelNode(title, 
            font=button_font,
            color=font_color,
            position=(0, 0),
            parent=self)
        self.title = title
        #self.color = 'lime' #background color

    def touch_began(self, touch):
        if self.title == '←':
            x, y = self.parent.sprite.position 
            self.parent.sprite.position = ((x-20) if (x-20) > 0 else x, y)        
        elif self.title == '→':
            x, y = self.parent.sprite.position 
            self.parent.sprite.position = ((x+20) if (x+20) < self.parent.size[0] else x, y)        
        elif self.title == '↓':
            x, y = self.parent.sprite.position 
            self.parent.sprite.position = (x, (y-20) if (y-20) > 0 else y)   
        elif self.title == '↑':      
            x, y = self.parent.sprite.position 
            self.parent.sprite.position = (x, (y+20) if (y+20) < self.parent.size[1] else y)   

class MyScene(scene.Scene):
    def setup(self):
        self.sprite = scene.SpriteNode('Dog_Face', position=self.size/2, parent=self)
        self.left_button = ButtonNode('←', 
            position=(self.size[0]/2.0 - 300, self.size[1]/2-300), parent=self)
        self.right_button = ButtonNode('→', 
            position=(self.size[0]/2.0-100, self.size[1]/2-300), parent=self)
        self.down_button = ButtonNode('↓', 
            position=(self.size[0]/2.0 +100, self.size[1]/2-300), parent=self)
        self.up_button = ButtonNode('↑', 
            position=(self.size[0]/2.0+300, self.size[1]/2-300), parent=self)

    def touch_began(self, touch):
        for node in self.children:
            if hasattr(node, 'touch_began'):
                if touch.location in node.frame:
                    node.touch_began(touch)

scene.run(MyScene())

ccc

@lachlantula One thing that is confusing to the reader is that the touch in touch.begin()is a scene.Touch object but touch in update_player() is a Boolean. Perhaps the second could be renamed was_touched or perhaps it could be removed and you could only call update_player() (with no parameters) when a touch happens.

lachlantula

@abcabc that works wonderfully - thanks so much for the help!
@ccc Thanks for picking up on that!

ccc

Using min() and max() simplifies keeping sprites in bounds...

import scene


class ButtonNode(scene.SpriteNode):
    def __init__(self, title, *args, **kwargs):
        scene.SpriteNode.__init__(self, 'pzl:Button1', *args, **kwargs)
        self.title = title
        scene.LabelNode(title, color='blue', font=('Avenir Next', 20),
                        parent=self, position=(0, 0))

    def touch_began(self, touch):
        sprite = self.parent.sprite
        x, y = sprite.position
        if self.title == '←':
            sprite.position = max(x - 20, 0), y
        elif self.title == '→':
            sprite.position = min(x + 20, self.parent.size.w), y
        elif self.title == '↓':
            sprite.position = x, max(y - 20, 0)
        elif self.title == '↑':
            sprite.position = x, min(y + 20, self.parent.size.h)


class MyScene(scene.Scene):
    def setup(self):
        center = self.size/2
        self.sprite = scene.SpriteNode('Dog_Face', parent=self, position=center)
        ButtonNode('←', parent=self, position=center - (300,  300))
        ButtonNode('→', parent=self, position=center - (100,  300))
        ButtonNode('↓', parent=self, position=center + (100, -300))
        ButtonNode('↑', parent=self, position=center + (300, -300))

    def touch_began(self, touch):
        for node in self.children:
            if touch.location in node.frame and hasattr(node, 'touch_began'):
                    node.touch_began(touch)


scene.run(MyScene())