Reputation: 41
I'm currently trying to make a platformer game for IOS/Android but I'm stuck on a problem. I've created two buttons and a character. I want the character to keep moving until the button is released. By that I mean: I can move the character once, when the button is pressed, but I want it to keep moving until the button is released.
I've tried multiple solution, for example I used pythons time module:
class Level1(Screen):
posx = NumericProperty(0)
posy = NumericProperty(0)
moving = True
i = 0
def __init__(self, **kwargs):
super(Level1, self).__init__(**kwargs)
def rightmove(self):
self.posx = self.posx+1
time.sleep(10)
def goright(self):
while self.moving == True:
self.rightmove()
i += 1
if i == 10:
break
def stopright(self):
self.moving == False
but it doesn't work. It think that it somehow is put in an endless loop, because when I press the button the app stop working ("app stopped working..." error).
I have pretty much no idea how I can fix this. I've been trying for the last few hours and havn't found a solution yet. Here's my .py file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition, SlideTransition
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, NumericProperty
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
import time
Config.set('graphics','resizable',0) #don't make the app re-sizeable
#Graphics fix
#this fixes drawing issues on some phones
Window.clearcolor = (0,0,0,1.)
language = "english"
curr1msg = 1
class HomeScreen(Screen):
pass
class OptionsScreen(Screen):
pass
class GameScreen(Screen):
pass
class LevelScreen(Screen):
pass
class Level1intro(Screen):
global language
global curr1msg
if language == "english" and curr1msg == 1:
pName = "Pedro"
msg1 = """Hello my friend!
My name is Pedro and I have a problem. Will you help me?
My spanish studens have a spanish test tomorrow, but I lost the exams!
You are the only one who can help me!"""
cont = "Press anywhere to continue..."
elif language == "swedish" and curr1msg == 1:
pName = "Pedro"
msg1 = """Hejsan!
Jag är Pedro och jag har ett problem. Kan du hjälpa mig?
Mina spanska-elever har ett spanskaprov imorgon men jag har tappat bort proven!
Du är den enda som kan hjälpa mig!"""
cont = "Tryck på skärmen för att fortsätta..."
class Level1(Screen):
posx = NumericProperty(0)
posy = NumericProperty(0)
moving = True
i = 0
def __init__(self, **kwargs):
super(Level1, self).__init__(**kwargs)
def rightmove(self):
self.posx = self.posx+1
time.sleep(10)
def goright(self):
while self.moving == True:
self.rightmove()
i += 1
if i == 10:
break
def stopright(self):
self.moving == False
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
And here is my .kv file:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
#: import SlideTransition kivy.uix.screenmanager.SlideTransition
ScreenManagement:
transition: FadeTransition()
HomeScreen:
OptionsScreen:
LevelScreen:
Level1intro:
Level1:
<HomeScreen>:
name: 'home'
FloatLayout:
canvas:
Rectangle:
source:"images/home_background.jpg"
size: self.size
Image:
source:"images/logo.png"
allow_stretch: False
keep_ratio: False
opacity: 1.0
size_hint: 0.7, 0.8
pos_hint: {'center_x': 0.5, 'center_y': 0.9}
Button:
size_hint: 0.32,0.32
pos_hint: {"x":0.34, "y":0.4}
on_press:
app.root.transition = SlideTransition(direction="left")
app.root.current = "level"
background_normal: "images/play_button.png"
allow_stretch: False
Button:
size_hint: 0.25,0.25
pos_hint: {"x":0.38, "y":0.15}
on_press:
app.root.transition = SlideTransition(direction="left")
app.root.current = 'options'
background_normal: "images/settings_button.png"
<OptionsScreen>:
name: 'options'
<LevelScreen>
name: "level"
FloatLayout:
canvas:
Rectangle:
source:"images/home_background.jpg"
size: self.size
Label:
text: "[b]Choose Level[/b]"
markup: 1
font_size: 40
color: 1,0.5,0,1
pos: 0,250
Button:
size_hint: 0.1,0.1
pos_hint: {"x": 0.1, "y": 0.8}
on_press:
app.root.current = "level1intro"
Image:
source:"images/level1.png"
allow_stretch: True
y: self.parent.y + self.parent.height - 70
x: self.parent.x
height: 80
width: 80
Button:
background_normal: "images/menu_button.png"
pos_hint: {"x": 0.4, "y": 0}
size_hint: 0.3,0.3
pos_hint: {"x": 0.35}
on_press:
app.root.transition = SlideTransition(direction="right")
app.root.current = "home"
<Level1intro>
name: "level1intro"
canvas:
Rectangle:
source: "images/background.png"
size: self.size
Image:
source: "images/dialog.png"
pos_hint: {"y": -0.35}
size_hint: 0.7,1.0
Label:
font_size: 20
color: 1,1,1,1
pos_hint: {"x": -0.385, "y": -0.285}
text: root.pName
Label:
font_size: 15
color: 1,1,1,1
pos_hint: {"x": -0.15, "y": -0.4}
text: root.msg1
Label:
font_size: 15
color: 0.7,0.8,1,1
pos_hint: {"x": 0.025, "y": -0.449}
text: root.cont
on_touch_down:
app.root.transition = FadeTransition()
app.root.current = "level1"
<Level1>
name: "level1"
canvas:
Rectangle:
source: "images/background.png"
size: self.size
Button:
text: ">"
size_hint: 0.1,0.1
pos_hint: {"x":0.9, "y":0.0}
on_press:
root.goright()
on_release:
root.stopright()
Button:
text: "<"
size_hint: 0.1,0.1
pos_hint: {"x": 0.0, "y": 0.0}
on_press:
root.posx = root.posx-1
Image:
id: char
source: "images/idle1.png"
size: self.size
pos: root.posx,root.posy
Thank you for your time and help. GryTrean
//I changed "i" to "self.i" and it doesn't fix the problem.
Upvotes: 4
Views: 3605
Reputation: 81
This took me a day to figure out:
Let say you want to have a button that has both short press (for event 1) and long press (for event 2).
# Button:
# id: btn6
# text:'Button6\nDown\nHold 3s'
# size_hint: (None,None)
# size:self.size
# on_press: root.hold_press(self)
# on_release: scrn_mnger.transition.direction = 'down'
# on_release: scrn_mnger.current = 'scrn_media'
In the python file:
from kivy.clock import Clock
def hold_press(self,inst):
if inst.state == 'down':
Clock.schedule_once(lambda x: self.long_press(),1)
def long_press(self):
if self.ids.btn6.state == 'down':
self.ids.scrn_mnger.transition.direction = 'left'
self.ids.scrn_mnger.current = 'scrn_media'
Upvotes: 0
Reputation: 451
According to the Kivy API, once the button is pressed, you can create an event. For example,
my_event = Clock.schedule_interval(rightmove, 0.5)
This event will call rightmove()
every 0.5 seconds. After creating the event, you can call it through -VariableName-(), so in this case we would put my_event()
.
Now, if we release the button, we need this to stop looping, so you can bind the button's on_release
attribute to preform the cancel()
function on the event. Something like this:
my_event.cancel()
or
Button(on_release=my_event.cancel)
Note: you will need my_event
to be a global variable so that the start and end functions can access it.
Upvotes: 4
Reputation: 4693
I have created a simple example for you, featuring how to move a character (in this case, elf warrior level 1) with a button press:
#!/usr/bin/env python3.5
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import mainthread, Clock
gui = '''
Root:
orientation: 'vertical'
arena: arena
control_button: control_button
Arena:
id: arena
Button
id: control_button
size_hint_y: None
height: dp(50)
text: 'move'
<Arena@FloatLayout>:
player: player
Button:
id: player
pos: 150, 300
text: 'elf warrior\\nlevel 1'
size_hint: None, None
size: 100, 100
'''
class Root(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
@mainthread
def job():
self.control_button.bind(on_press=self._on_press)
self.control_button.bind(on_release=self._on_release)
job()
def _on_press(self, button):
self.arena.start_movement()
def _on_release(self, button):
self.arena.stop_movement()
class Arena(FloatLayout):
def start_movement(self):
Clock.schedule_interval(self._move_right, 0.01)
def stop_movement(self):
Clock.unschedule(self._move_right)
def _move_right(self, dt):
self.player.x += 1
class Test(App):
def build(self):
return Builder.load_string(gui)
Test().run()
Upvotes: 4