That's my error:
AttributeError: 'NoneType' object has no attribute 'move'
I have been searching, looking kivy videos and trying a lot of things but I can't get the ball of the Pong Game tutorial to work on my GameScreen when I press Play in StartScreen.
Sometimes i don't get an error but only when the game isn't on the screen. The app then works normally and the ball (snake snaky) does show on the right SnakeWidget widget, but i can't change its position even with typing the exact position.
.py:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.core.image import Image
from kivy.graphics import Color, Rectangle
from kivy.uix.popup import Popup
from kivy.uix.bubble import Bubble
from kivy.properties import NumericProperty, ReferenceListProperty
from kivy.properties import ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.lang import Builder
from random import randint
class InfoWidget(Widget):
score = NumericProperty(0)
class Snake(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class SnakeWidget(Widget):
snaky = ObjectProperty(None)
def __init__(self, *args, **kwargs):
super(SnakeWidget, self).__init__(*args, **kwargs)
Clock.schedule_interval(self.update, 1.0 / 60.0)
def begin(self, vel=(4, 0)):
self.snaky.center = self.center
self.snaky.velocity = vel
def update(self, dt):
self.snaky.move()
class InfoWidget(Widget):
score = NumericProperty(0)
class StartScreen(Screen):
snake_widget = SnakeWidget()
Clock.schedule_interval(snake_widget.update, 1.0 / 60.0)
class GameScreen(Screen):
pass
class RootScreen(ScreenManager):
pass
class Main2App(App):
def build(self):
self.load_kv("main2.kv")
return RootScreen()
if __name__ == "__main__":
Main2App().run()
.kv file:
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<StartScreen>:
name: "start"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "lights.png"
FloatLayout:
Button:
id: "play"
background_color: 0.012, 0.227, 0.11, 0.1
text: "Play!"
size_hint: 0.4, 0.3
pos_hint: {'center_x':.5, 'center_y':.5}
font_size: 70
on_release: root.current = 'game'; snake_widget.begin()
Button:
id: "how"
background_color: 0.012, 0.227, 0.11, 0.1
text: "How to play"
size_hint: 0.4, 0.1
pos_hint: {"center_x":.5, "center_y":.3}
font_size: 40
<GameScreen>:
name: "game"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "lights.png"
FloatLayout:
SnakeWidget:
InfoWidget:
Button:
id: menu
size_hint: 0.2, 0.1
pos_hint: {"x": 0.8,"y":0.9}
background_color: 0.012, 0.227, 0.11,0.3
text: "Menu"
font_size: 17
on_release: root.manager.current = "start"
Button:
id: levo
size_hint: 0.1, 0.1
pos_hint: {"x": 0.8,"y":0}
background_color: 0.012, 0.227, 0.11,0.3
text: "<"
font_size: 20
Button:
id: desno
size_hint: 0.1, 0.1
pos_hint: {"x": 0.9,"y":0}
background_color: 0.012, 0.227, 0.11,0.3
text: ">"
font_size: 20
<Snake>:
size: 50, 50
canvas:
Color:
rgba: 1,1,1,1
Ellipse:
pos: self.pos
size: 40, 40
source: "snaky.png"
<SnakeWidget>:
id: snake_widget
snaky: snake
size_hint: 0.797, 1
pos_hint: {"x": 0,"center_y":0.5}
canvas:
Color:
rgba: 1,1,1,0.07
Rectangle:
size: self.size
pos: self.pos
Snake:
id: snake
center: self.parent.center
<InfoWidget>:
size_hint: 0.2, 0.799
pos_hint: {"x": 0.8014,"y":0.101}
canvas.before:
Color:
rgba: 0.010, 0.227, 0.17, 0.005
Rectangle:
size: self.size
pos: self.pos
Label:
canvas.before:
Color:
rgba: 0.010, 0.227, 0.17, 0.005
Rectangle:
size: root.parent.width*0.192, root.parent.height*0.06
pos: root.parent.width*0.805, root.parent.height*0.837
id: "result"
text: "Result:"
font_size: 17
pos: root.parent.width*0.79, root.parent.height*0.78
Label:
canvas.before:
Color:
rgba: 0.012, 0.227, 0.15, 0.005
Rectangle:
size: root.parent.width*0.192, root.parent.height*0.06
pos: root.parent.width*0.805, root.parent.height*0.77
id: "record"
text: "Record:"
font_size: 17
pos: root.parent.width*0.79, root.parent.height*0.72
<RootScreen>:
id: screen_manager
transition: FadeTransition()
StartScreen:
name: "start"
GameScreen:
name: "game"
Sorry for all the code, but I really don't know what to try anymore.
In line 35,
class SnakeWidget(Widget):
snaky = ObjectProperty(Snake())
Snaky should be an instance of Snake.
Try something Like this:
.py is here...
class PongPaddle(Widget):
score = NumericProperty(0)
def bounce_ball(self, ball):
if self.collide_widget(ball):
vx, vy = ball.velocity
offset = (ball.center_y - self.center_y) / (self.height / 2)
bounced = Vector(-1 * vx, vy)
vel = bounced * 1.1
ball.velocity = vel.x, vel.y + offset
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class PongGame(Widget):
ball = ObjectProperty(None)
player1 = ObjectProperty(None)
player2 = ObjectProperty(None)
def __init__(self, *args, **kwargs):
super(PongGame, self).__init__(*args, **kwargs)
Clock.schedule_interval(self.update, 1.0 / 60.0)
def serve_ball(self, vel=(4, 0)):
self.ball.center = self.center
self.ball.velocity = vel
def update(self, dt):
self.ball.move()
#bounce of paddles
self.player1.bounce_ball(self.ball)
self.player2.bounce_ball(self.ball)
#bounce ball off bottom or top
if (self.ball.y < self.y) or (self.ball.top > self.top):
self.ball.velocity_y *= -1
#went of to a side to score point?
if self.ball.x < self.x:
self.player2.score += 1
self.serve_ball(vel=(4, 0))
if self.ball.x > self.width:
self.player1.score += 1
self.serve_ball(vel=(-4, 0))
def on_touch_move(self, touch):
if touch.x < self.width / 3:
self.player1.center_y = touch.y
if touch.x > self.width - self.width / 3:
self.player2.center_y = touch.y
class Manager(ScreenManager):
pass
class GameApp(App):
def build(self):
self.load_kv('t6.kv')
return Manager(transition=WipeTransition())
if __name__ == '__main__':
GameApp().run()
and .kv is here...
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
<PongPaddle>:
size: 25, 200
canvas:
Rectangle:
pos:self.pos
size:self.size
<PongGame>:
ball: pong_ball
player1: player_left
player2: player_right
canvas:
Rectangle:
pos: self.center_x-5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 50
text: str(root.player1.score)
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.top - 50
text: str(root.player2.score)
PongBall:
id: pong_ball
center: self.parent.center
PongPaddle:
id: player_left
x: root.x
center_y: root.center_y
PongPaddle:
id: player_right
x: root.width-self.width
center_y: root.center_y
<Manager>:
id: screen_manager
Screen:
name: 'home'
Button:
text: 'Play Ping Pong'
halign: 'center'
valign: 'middle'
font_size: 100
text_size: self.size
on_release: root.current = 'game';game.serve_ball()
Screen:
name: 'game'
PongGame:
id: game
Hope this would help...
Related
I am currently practicing on making apps on kivy. I tried making a button on top left corner
with an icon of a home to send back to main page. Issue is, if I ask it to load jpg files, it works just fine. But if I try loading png files, I can see the image loading for just a millisecond before instantly closing down. Here is my python code:
# super().__init__(**kwargs)
from kivy.config import Config
from kivy.metrics import dp
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, NoTransition, Screen
Config.set("graphics", "width", "360")
Config.set("graphics", "height", "640")
# Global Variables
class MainScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class PlayButtons(BoxLayout):
def on_play_press(self):
self.parent.parent.parent.manager.current = 'tanks_screen'
pass
class MainScreenTitle(Screen):
title_str = 'TANKS'
title = StringProperty(title_str)
title_font_width_ratio = 1 / (len(title_str) - 0.5 * title_str.count(' '))
class TanksScreen(Screen):
def on_main_menu_press(self):
print(self)
pass
class GameApp(App):
def build(self):
sm = ScreenManager(transition=NoTransition())
sm.add_widget(MainScreen(name='main_screen'))
sm.add_widget(TanksScreen(name='tanks_screen'))
return sm
GameApp().run()
Here is my kv file:
<MainScreen>:
FloatLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "images/imagetest.jpg"
FloatLayout:
PlayButtons:
size_hint: .5,.15
pos_hint: {"center_x":.5, "center_y":.4}
MainScreenTitle:
size_hint: .8, .15
pos_hint: {"center_x":.5,"center_y":.75}
<MainScreenTitle>:
BoxLayout:
FloatLayout:
Widget:
pos_hint: {'center_x':0.5, 'center_y': 0.5}
size: self.size
canvas:
Color:
rgb: 1,.2,.15
RoundedRectangle:
size: self.width - self.height * 0.15, self.height * 0.85
pos: self.x + self.height * 0.075, self.y + self.height * 0.075
Color:
rgb: 0,0,0
Line:
width: dp(2)
points:
(
self.x, self.y,
self.x + self.width,
self.y, self.x + self.width,
self.y + self.height,
self.x ,self.y + self.height,
self.x, self.y
)
Label:
id: TITLE
font_size: int(self.width * root.title_font_width_ratio) if int(self.width * root.title_font_width_ratio) <= self.height else self.height
size: self.size
text: root.title
pos_hint: {"center_x":.5,"center_y":.5}
<PlayButtons>
FloatLayout:
Button:
on_press: root.on_play_press()
text: "Play"
size_hint: 1,.4
pos_hint: {"center_x":.5,"top":1}
Button:
text: "Settings"
size_hint: 1,.4
pos_hint: {"center_x":.5,"top":.2}
<TanksScreen>:
BoxLayout:
FloatLayout:
Widget:
canvas.before:
Rectangle:
size: self.size
pos: self.pos
source: "images/home.png"
Button:
background_color: 0,0,0,0
size_hint: .2,.2
pos_hint: {"x":0,"top":1}
on_press: root.on_main_menu_press()
I am specifically talking about the last few lines. If I ever try loading a png file, it wont work. Only jpeg files are working well. Any ideas why?
I'm making a game in kivy, it's a soccer juggling game. I want the game to be over whenever the soccer ball falls off the screen, also I want a restart button when the game is over so I can play again. I tried a lot of things but it doesn't seem to work. Any help is appreciated. Below is my code! Thank You!
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.image import Image
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.vector import Vector
class HomeScreen(Screen):
pass
def play_sound(self):
sound = SoundLoader.load('button press sound.wav.')
if sound:
sound.play()
sound = SoundLoader.load('Crowd sound effect.wav')
sound.loop = True
sound.play()
class GameScreen(Screen):
pass
def play_sound(self):
sound = SoundLoader.load('button press sound.wav.')
if sound:
sound.play()
class Ball(Image):
velocity = NumericProperty(0)
def on_touch_down(self, touch):
if Vector(self.center).distance(touch.pos) <= 33:
label = App.get_running_app().root.get_screen('game_screen').ids.score
label.text = str(int(label.text) + 1)
sound = SoundLoader.load('Soccer ball sound.wav')
sound.play()
self.source = "icons/ball.png"
self.velocity = 275
return super().on_touch_down(touch)
def on_touch_up(self, touch):
if Vector(self.center).distance(touch.pos) <= 33:
self.source = "icons/ball.png"
return super().on_touch_up(touch)
class MainApp(App):
GRAVITY = 300
def move_ball(self, time_passed):
ball = self.root.ids.game_screen.ids.ball
ball.y = ball.y + ball.velocity * time_passed
ball.velocity = ball.velocity - self.GRAVITY * time_passed
self.check_collision()
def check_collision(self):
ball = self.root.ids.game_screen.ids.ball
if ball.top < 96:
self.game_over()
def game_over(self):
print("game over")
def start_game(self):
Clock.schedule_interval(self.move_ball, 1/60.)
self.root.ids.game_screen.ids.score.text = "0"
def change_screen(self, screen_name):
self.root.current = screen_name
MainApp().run()
homescreen.kv
#:import utils kivy.utils
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<HomeScreen>:
FloatLayout:
canvas:
Color:
rgb: utils.get_color_from_hex("#39B3F2")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 1
pos_hint: {"top": 1, "left": 1}
size_hint: 1, .9
Image:
source: "icons/keepyup.png"
FloatLayout:
Button:
font_size: dp(20)
font_name: 'SackersGothicStd-Medium.otf'
text: "PLAY"
color: "gold"
pos_hint: { "center_x": .5, "center_y": .3}
size: 80, 55
size_hint: None, None
background_normal: ''
background_color: (57/255.0, 179/255.0, 242/255.0, .10)
on_press:
on_release:
root.play_sound()
root.manager.transition = FadeTransition()
app.change_screen("game_screen")
gamescreen.kv
#:import utils kivy.utils
<GameScreen>:
FloatLayout:
canvas:
Color:
rgb: utils.get_color_from_hex("#39B3F2")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 1
pos_hint: {"top": 1, "left": 1}
size_hint: 1, .1
Image:
source: "icons/sun.png"
GridLayout:
rows: 1
pos_hint: {"top": 1, "left": 1}
size_hint: 1, .2
Image:
source: "icons/clouds.png"
GridLayout:
rows: 1
pos_hint: {"bottom": 1, "left": 1}
size_hint: 1, .5
Image:
source: "icons/Field4.png"
allow_stretch: True
keep_ratio: False
pos: self.pos
Label:
id: score
size_hint: None, None
font_size: dp(25)
font_name: 'SackersGothicStd-Medium.otf'
text: "0"
color: "gold"
pos_hint: { "center_x": 0.1, "center_y": 0.9}
Button:
size_hint: None, None
font_size: dp(20)
font_name: 'SackersGothicStd-Medium.otf'
text: "Start Game"
color: "gold"
pos_hint: { "center_x": 0.5, "center_y": 0.3}
size: 150, 55
size_hint: None, None
background_normal: ''
background_color: (57/255.0, 179/255.0, 242/255.0, .10)
on_release:
self.disabled = True
self.opacity = 0
root.play_sound()
app.start_game()
Ball:
source: "icons/ball.png"
size_hint: None, None
size: 500, 500
pos_hint: {"center_x": 0.5}
id: ball
main.kv
#:include kv/homescreen.kv
#:include kv/gamescreen.kv
ScreenManager:
id: screen_manager
HomeScreen:
name: "home_screen"
id: home_screen
GameScreen:
name: "game_screen"
id: game_screen
Firstly, define a name for clock so you can stop it when game over:
self.control = Clock.schedule_interval(self.move_ball, 1/60.)
In game_over func, let's stop this clock:
self.control.cancel()
Now we need to create BoxLayout for our popup: ( game_over function )
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
bx = BoxLayout(orientation='vertical')
restart_but = Button(text='Restart')
restart_but.bind(on_release=self.restart_game)
bx.add_widget(Label(text='Score :'+self.root.ids.game_screen.ids.score.text))
bx.add_widget(restart_but)
self.popup = Popup(title='Game Over',content=bx,size_hint=(None, None), size=(400, 400))
self.popup.open()
Now as we define release command to restart_but, need to create new function:
def restart_game(self,*args):
self.popup.dismiss() #Close popup
#default settings here..
self.control = Clock.schedule_interval(self.move_ball, 1/60.) #Start Game
In restart_game function, you need to reset all settings like ball's position and score.
Also I suggest you to use KivyMD for sightly popups and buttons.
First I want to say I just started learning maybe 2 months ago so I don't really know how to phrase my question. so if the Question title is misleading I'm sorry.
basically I'm working on a project and I want to learn how to add projects I've already done inside an like the pong game (pong.py and pong.kv) I made and I want to see if I can use the simple app (main.py, main.kv, playscreen.kv, settingscreen.kv, aboutscreen.kv)I made to run the pong game. Basically I'm trying to make the main app be able to navigate to the playscreen and then be able to play pong
I cant even remember all the things I've tried but when I think I get close I end up seeing a black screen or I just see the pong screen which is the problem I'm having now.
Main.py
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.screen import Screen
class HomeScreen(Screen):
pass
class SettingScreen(Screen):
pass
class AboutScreen(Screen):
pass
class PlayScreen(Screen):
pass
class PlayPong(Screen):
pass
#GUI = Builder.load_file("main.kv")
class MainApp(MDApp):
def build(self):
self.root = Builder.load_file("main.kv")
self.theme_cls.primary_palette = "Teal"
def change_screen(self,screen_name):
screen_manager = self.root.ids['screen_manager']
screen_manager.current = screen_name
ScreenManager.transition
#screen_manager.play_pong = Builder.load_file("kv/pong.py")
if __name__ == "__main__":
MainApp().run()
Main.kv
#:include kv/homescreen.kv
#:include kv/settingscreen.kv
#:include kv/aboutscreen.kv
#:include kv/playscreen.kv
#:include kv/playpong.kv
GridLayout:
cols: 1
ScreenManager:
id: screen_manager
HomeScreen:
name: "home_screen"
id: home_screen
SettingScreen:
name: "setting_screen"
id: setting_screen
AboutScreen:
name:"about_screen"
id: about_screen
PlayScreen:
name:"play_screen"
id: play_screen
PlayPong:
name: "play_pong"
id: "play_pong"
playpong.kv
#:import PongApp kv.pong.PongApp
#:import App kivy.app.App
<PlayPong>:
#PongApp().run()
homescreen.kv
#:include kivymd/MDApp.py
#:include kivymd/uix/button.py/MDFloatingActionButton/MDFlatButton
#:include kivymd/uix/screen.py/Screen
#:import MDFillRoundFlatButton kivymd.uix.button.MDFillRoundFlatButton
#:import Builder kivy.lang.Builder
<HomeScreen>:
FloatLayout:
BoxLayout:
orientation: 'horizontal'
MDToolbar:
pos_hint: {"center_x": .95, "center_y": .97}
title: 'Main Menu'
elevation:10
left_action_items: [["home", lambda x: x]]
right_action_items: [["book", lambda x: x]]
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .3}
size_hint: .8,.1
md_bg_color: [.200,.150,.150,.3]
text: "Settings"
on_release:
app.change_screen("setting_screen")
root.manager.transition.direction = 'right'
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .5}
size_hint: .8,.1
md_bg_color: [.200,.150,.150,.3]
text: "about"
on_release:
app.change_screen("about_screen")
root.manager.transition.direction = 'right'
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .7}
size_hint: .8,.1
md_bg_color: [.200,.150,.150,.3]
text: "play"
on_release:
app.change_screen("play_screen")
root.manager.transition.direction = 'right'
playscreen.kv
<PlayScreen>:
FloatLayout:
BoxLayout:
orientation: 'horizontal'
MDToolbar:
pos_hint: {"center_x": .95, "center_y": .95}
title: 'Game Menu'
elevation:10
left_action_items: [["devices", lambda x: x]]
right_action_items: [["gesture", lambda x: x]]
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .5}
size_hint: .6,.1
text: "Main Menu"
md_bg_color: [.200,.150,.150,.3]
on_release:
app.change_screen("home_screen")
root.manager.transition.direction = 'right'
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .3}
size_hint: .6,.1
text: "Play Pong"
md_bg_color: [.200,.150,.150,.3]
on_release:
app.change_screen("play_pong")
root.manager.transition.direction = 'right'
settingscreen.kv
#:include kivymd/MDApp.py
#:include kivymd/uix/button.py/MDFloatingActionButton/MDFlatButton
#:include kivymd/uix/screen.py/Screen
#:import MDFillRoundFlatButton kivymd.uix.button.MDFillRoundFlatButton
#:import Builder kivy.lang.Builder
<SettingScreen>:
FloatLayout:
BoxLayout:
orientation: 'horizontal'
MDToolbar:
pos_hint: {"center_x": .95, "center_y": .95}
title: 'Settings'
left_action_items: [["settings", lambda x: x]]
right_action_items: [["dns", lambda x: x]]
elevation:10
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .5}
size_hint: .6,.1
text: "Main Menu"
md_bg_color: [.200,.150,.150,.3]
on_release:
app.change_screen("home_screen")
root.manager.transition.direction = 'left'
aboutscreen.kv
<AboutScreen>:
FloatLayout:
BoxLayout:
orientation: 'horizontal'
MDToolbar:
pos_hint: {"center_x": .95, "center_y": .95}
title: 'About The Game and Creator'
elevation:10
left_action_items: [["emoticon", lambda x: x]]
right_action_items: [["library", lambda x: x]]
Label:
pos_hint: {"top":.9 , "left":.5}
size_hint: 1,.2
text:
"About the app and the creator"
MDFillRoundFlatButton:
pos_hint: {"center_x": .5, "center_y": .5}
size_hint: .6,.1
text: "Main Menu"
on_release:
app.change_screen("home_screen")
root.manager.transition.direction = 'right'
pong.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint
class PongPaddle(Widget):
score = NumericProperty(0)
def bounce_ball(self,ball):
if self.collide_widget(ball):
ball.velocity_x *= -1.1
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x,velocity_y)
# latest postion = Current velocity + Current Position
def move(self):
self.pos = Vector(*self.velocity) + self.pos
# moving the ball by calling move function
class PongGame(Widget):
ball = ObjectProperty(None)
player1 = ObjectProperty(None)
player2 = ObjectProperty(None)
def serve_ball(self):
self.ball.velocity = Vector(4, 0).rotate(randint(0,360))
def update(self, dt):
self.ball.move()
# bounce off top and bottom
if (self.ball.y < 0) or (self.ball.y > self.height -30):
self.ball.velocity_y *= -1
# bounce off left and increase score
if self.ball.x < -30:
self.ball.velocity_x *= -1
self.player1.score += 1
# bounce of right
if self.ball.x > self.width:
self.ball.velocity_x *= -1
self.player2.score += 1
self.player1.bounce_ball(self.ball)
self.player2.bounce_ball(self.ball)
def on_touch_move(self, touch):
if touch.x < self.width / 1/4:
self.player1.center_y = touch.y
if touch.x > self.width * 3/4:
self.player2.center_y = touch.y
class PongApp(App):
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update,0/60.0)
return game
if __name__ == "__main__":
PongApp().run()
pong.kv
<PongPaddle>:
size: 20,200
canvas:
Color:
rgba: 1,0,0,1
Rectangle:
pos: self.pos
size: self.size
<PongBall>:
size: 30,30
canvas:
Ellipse:
pos: self.pos
size: self.size
<PongGame>:
ball : pong_ball
player1 : player_left
player2 : player_right
canvas:
Color:
rgba: 0,0,1,1
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.top - 30
text: str(root.player2.score)
Label:
font_size: 70
center_x: root.width * 3/4
top: root.top - 30
text: str(root.player1.score)
PongBall:
id : pong_ball
center: self.parent.center
PongPaddle:
id:player_left
x : root.x
center_y : root.center_y
PongPaddle:
id:player_right
x : root.width - self.width
center_y : root.center_y
So after I updated my app I'm still getting a widget error
1:from kivy.app import App
>> 2:from kivy.uix.widget import Widget
3:from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
4:from kivy.vector import Vector
...
Only one root object is allowed by .kv
Ive tried playing with the classes to try and only make one widget but then that messes up the code and I get other errors
I've also tried writing all the Pong.py code into my Main.py file but that didn't seem to work either.
Anyways thanks for the help!
The reason that you are seeing the pong game is because of the line:
PongApp().run()
Which starts the pong game as soon as you import that file.
Replace that line with:
if __name__ == "__main__":
PongApp().run()
That protects the running of PongApp unless pong.py is run directly by python, and not just imported.
I'm trying to periodically run the animation of canvas circle line by changing its angle using a numeric property called "level" so it refreshes every second by creating a Clock object but the animation simply won't run. In the other hand I also have a different method been called from the .kv file when user inputs 'r' in a text input that animates that "level" numeric property and the animation runs perfectly.
I've noticed that in both cases the value of "level" is different as if there were 2 different instances of level. I do not understand what is going on, can some one shed some light on what I'm doing wrong?
Notice that the animation is affecting the widgets with id "gauge and needle" on my .kv file under the "tachometer" commented section
import kivy
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.properties import *
from kivy.animation import Animation
import kivy.graphics
from kivy.clock import Clock
from math import cos, sin, pi
from functools import partial
import random
def rpm_conversion(rpm):
return (rpm * (180.5/8000) -135.5)
####################################################
#---------------------- GUI -----------------------#
class DataWindow(GridLayout):
def rpmupdate(self,dt):
rand = random.randint(0,8000)
gaugranim = Animation(level = rpm_conversion(float(rand)))
print("Timer triggered: " + str(self.level))
self.rpm = int(rand)
gaugranim.start(self)
def on_enter(self, value):
print(value[5:] )
self.display.text = "ecu> "
rand = random.randint(0,8000)
if(value[5:] == "r"):
anim = Animation(level = rpm_conversion(float(rand)) )
print("User triggered: " + str(self.level))
self.rpm = int(rand)
anim.start(self)
#Keeps user from deleting name in console
def bashlook(self,value, crs):
if(value[:5] != 'ecu> '):
self.display.text = "ecu> "
class OpensecuApp(App):
def build(self):
clock = DataWindow()
Clock.schedule_interval(clock.rpmupdate, 2)
return DataWindow()
if __name__ == '__main__':
OpensecuApp().run()
.kv:
#:import math math
[GaugeNumber#Label]:
text: str(ctx.i)
pos_hint: {"center_x": 0.5+0.42*math.sin(math.pi/8*(ctx.i-6)), "center_y": 0.5+0.42*math.cos(math.pi/8*(ctx.i-6))}
font_size: self.height/24
<DataWindow>:
id: opensecu
display: cmd
level: -135
rpm: 0
# Main window
rows:2
spacing: 10
padding: 10
canvas:
Color:
rgba: 0.1,0.1,0.1,1
Rectangle:
pos: self.pos
size: self.size
##########################################################
GridLayout:
size_hint: 1,1
cols: 3
#-------------------------- Data -----------------------------#
#Data
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 1"
#---------------------- Tachometer RPM ------------------------#
BoxLayout:
size_hint: 1.5,1
canvas.before:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
FloatLayout: #gauges numers
size_hint:None,None
size: (min(self.parent.size) * 0.95 ) , (min(self.parent.size) * 0.95 )
GaugeNumber:
i: 0
GaugeNumber:
i: 1
GaugeNumber:
i: 2
GaugeNumber:
i: 3
GaugeNumber:
i: 4
GaugeNumber:
i: 5
GaugeNumber:
i: 6
GaugeNumber:
i: 7
GaugeNumber:
i: 8
AnchorLayout: #gauges dots
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.68 ) , (min(self.parent.size) * 0.68 )
Image:
source: "resources/gauge.png"
size: self.texture_size
AnchorLayout: #gauges level rail
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0.1,0.1,0.1,1
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135.5, 45, 500)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
AnchorLayout: #gauge's levels
id: gauge
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135, root.level , 50)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
AnchorLayout: #blue line in gauge
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.width, self.height) / 100
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, 0, 360 , 50)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , (min(self.parent.size) * 0.38 )
BoxLayout: #gauge real time RPMS
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: str(int(root.rpm))
pos_hint: {"center_x": 0.5, "center_y": 0.65}
font_size: self.height / 6
BoxLayout:#gauges RPM note
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "RMP"
pos_hint: {"center_x": 0.5, "center_y": 0.35}
font_size: self.height / 12
BoxLayout:#gauges x1000
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "x1000"
pos_hint: {"center_x": 0.5, "center_y": 0.25}
font_size: self.height / 10
FloatLayout: #gauges needle
id: needle
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.60 ) , (min(self.parent.size) * 0.60 )
Image:
source: "resources/needle.png"
size: self.texture_size
pos_hint: {'center_x': .5, 'center_y': .5}
canvas.before:
PushMatrix
Rotate:
angle: (root.level)* (-1)
origin: self.center
canvas.after:
PopMatrix
#------------------------ Volumetric Efficiency Table -------------------------#
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 3"
###################################################################
#------------------------ Console -------------------------#
BoxLayout:
size_hint: 1,0.3
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
TextInput:
id: cmd
text: "ecu> "
background_color: 0.12,0.1195,0.122,1
foreground_color: 1,1,1,1
boold: 1
padding: 15
multiline: False
on_text: opensecu.bashlook(self.text, self.cursor)
on_text_validate: opensecu.on_enter(self.text)
# on_key_down:opensecu.on_enter(self.text)
The solution I found was creating object properties so I could have specific custom properties for each widget I needed to add animation.
python:
import kivy
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.uix.textinput import TextInput
from kivy.properties import *
from kivy.animation import *
import kivy.graphics
from kivy.clock import Clock
from math import cos, sin, pi
from functools import partial
import random
def rpm_conversion(rpm):
return (rpm * (180.5/8000) -135.5)
####################################################
#---------------------- GUI -----------------------#
class Gaugenumber(Label)
class OpensecuGauge(AnchorLayout):
gauge_level = NumericProperty(-135)
def gauge_anim(self,dt):
anim = Animation(gauge_level = rpm_conversion(float(readings[0])), d=0.5 )
anim.start(self)
class OpensecuNeedle(Image):
needle_level = NumericProperty(-135)
def needle_anim(self,dt):
# print(level)
anim = Animation(needle_level = rpm_conversion(float(readings[0])) , d=0.5)
anim.start(self)
class OpensecuWindow(GridLayout):
gauge = ObjectProperty(None)
needle = ObjectProperty(None)
def start(self):
Clock.schedule_interval(self.gauge.gauge_anim, 0.5)
Clock.schedule_interval(self.needle.needle_anim, 0.5)
Clock.schedule_interval(self.rpm_update, 0.5)
def rpm_update(self,dt):
anim = Animation(rpm = float(readings[0]), d=0.5)
anim.start(self)
def on_enter(self, value):
print(value[5:] )
self.display.text = "ecu> "
rand = random.randint(0,8000)
# print(self.gauge.level)
if(value[5:] == "r"):
pass
elif(value[5:]=="connect"):
cnnct()
self.start()
elif(value[5:]=="exit"):
stp()
else:
pass
#Keeps user from deleting name in console
def bashlook(self,value, crs):
if(value[:5] != 'ecu> '):
self.display.text = "ecu> "
class OpensecuApp(App):
def build(self):
# clock = OpensecuWindow()
# Clock.schedule_interval(clock.gauge.rpmupdate, 2)
connection = OpensecuWindow()
connection.start()
return OpensecuWindow()
if __name__ == '__main__':
OpensecuApp().run()
exit()
.kv:
#:import math math
[GaugeNumber#Label]:
text: str(ctx.i)
pos_hint: {"center_x": 0.5+0.42*math.sin(math.pi/8*(ctx.i-6)), "center_y": 0.5+0.42*math.cos(math.pi/8*(ctx.i-6))}
font_size: self.height/24
<OpensecuGauge>:
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
<OpensecuNeedle>:
source: "resources/needle.png"
size: self.texture_size
pos_hint: {'center_x': .5, 'center_y': .5}
canvas.after:
PopMatrix
<OpensecuWindow>:
id: opensecu
display: cmd
needle: needle
gauge: gauge
# level: -135
# needle_level: -135
rpm: 0
# Main windows
rows:2
spacing: 10
padding: 10
canvas:
Color:
rgba: 0.1,0.1,0.1,1
Rectangle:
pos: self.pos
size: self.size
##########################################################
GridLayout:
size_hint: 1,1
cols: 3
#-------------------------- Data -----------------------------#
#Data
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 1"
#---------------------- Tachometer RPM ------------------------#
BoxLayout:
size_hint: 1.5,1
canvas.before:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
FloatLayout: #gauges numers
size_hint:None,None
size: (min(self.parent.size) * 0.95 ) , (min(self.parent.size) * 0.95 )
GaugeNumber:
i: 0
GaugeNumber:
i: 1
GaugeNumber:
i: 2
GaugeNumber:
i: 3
GaugeNumber:
i: 4
GaugeNumber:
i: 5
GaugeNumber:
i: 6
GaugeNumber:
i: 7
GaugeNumber:
i: 8
AnchorLayout: #gauges dots
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.68 ) , (min(self.parent.size) * 0.68 )
Image:
source: "resources/gauge.png"
size: self.texture_size
OpensecuGauge: #gauges level rail
canvas.before:
Color:
rgba: 0.1,0.1,0.1,1
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135.5, 45, 500)
cap: 'none'
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
OpensecuGauge: #gauges levels
id: gauge
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135, self.gauge_level , 50)
cap: 'none'
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
AnchorLayout: #blue line in gauge
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.width, self.height) / 100
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, 0, 360 , 50)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , (min(self.parent.size) * 0.38 )
BoxLayout: #gauge real time RPMS
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: str(int(root.rpm))
pos_hint: {"center_x": 0.5, "center_y": 0.65}
font_size: self.height / 6
BoxLayout:#gauges RPM note
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "RMP"
pos_hint: {"center_x": 0.5, "center_y": 0.35}
font_size: self.height / 12
BoxLayout:#gauges x1000
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "x1000"
pos_hint: {"center_x": 0.5, "center_y": 0.25}
font_size: self.height / 10
FloatLayout: #gauges needle
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.60 ) , (min(self.parent.size) * 0.60 )
OpensecuNeedle:
id: needle
canvas.before:
PushMatrix
Rotate:
angle: (self.needle_level)* (-1)
origin: self.center
#------------------------ Volumetric Efficiency Table -------------------------#
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 3"
###################################################################
#------------------------ Console -------------------------#
BoxLayout:
size_hint: 1,0.3
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
TextInput:
id: cmd
text: "ecu> "
background_color: 0.12,0.1195,0.122,1
foreground_color: 1,1,1,1
boold: 1
padding: 15
multiline: False
on_text: opensecu.bashlook(self.text, self.cursor)
on_text_validate: opensecu.on_enter(self.text)
# on_key_down:opensecu.on_enter(self.text)
I want my CustomLabels and CustomToggleButtons, which I have created, to change their sizes according to different Window sizes. So this was what I did.
lbl = CustomLabel(text=text, width=self.grid_layout.width, >height=self.grid_layout.height*.5)
btn = CustomToggleButton(group=text, text=config_type[i], width=40 + >len(config_type[i]) * 20, height=self.grid_layout.height * .5)
What I did was set the above widgets' heights and widths above proportionate to a GridLayout containing them. The GridLayout's size is relative to the MainScreen. So if I change the Window size, the GridLayout would follow, followed by the widgets.
However, it did not work. Whenever I change the Window size, the CustomLabels and ToggleButtons would remain the same in size. Would appreciate some help, thanks!
This is the full code:
Builder.load_string('''
#:import hex kivy.utils.get_color_from_hex
<CustomButton>
font_size: self.width * .1
background_color: hex('#669999')
<CustomToggleButton>:
background_color: hex('#669999')
font_size: self.height*.5
size_hint: None, None
# height: self.parent.parent.height * .1
<CustomLabel>:
font_size: self.height * .5
size_hint: None, None
text_size: self.size
halign: 'left'
# width: self.parent.parent.width
# height: self.parent.parent.height * .1
<CustomBoxLayout>:
orientation: 'vertical'
<CustomStackLayout>:
size_hint_y: None
height: self.minimum_height
spacing: 10
<TempBoxLayout>:
spacing: 10
CustomBoxLayout:
spacing: 10
CustomButton:
text: 'Temp Up'
CustomButton:
text: 'Temp Down'
Label:
text: '20'
font_size: self.width * .1
canvas.before:
Color:
rgba: hex('#000000')
Rectangle:
pos: self.pos
size: self.size
<MainScreen>:
grid_layout: grid_layout
CustomBoxLayout:
padding: 10
spacing: 10
canvas.before:
Color:
rgba: hex('#669999')
Rectangle:
size: self.size
pos: self.pos
GridLayout:
id: grid_layout
canvas.before:
Color:
rgba: hex('#000000')
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_y: .4
BoxLayout:
size_hint_x: .25
TempBoxLayout:
BoxLayout:
size_hint_x: .25
''')
class CustomButton(Button):
pass
class CustomToggleButton(ToggleButton):
pass
class CustomLabel(Label):
pass
class CustomBoxLayout(BoxLayout):
pass
class CustomStackLayout(StackLayout):
pass
class TempBoxLayout(BoxLayout):
pass
class MainScreen(Screen):
store = JsonStore('remote_config.json')
power = str(store['power'][0])
mode = str(store['modes'][0])
fan_speed = str(store['fan_speed'][0])
swing = str(store['swing'][0])
louver = str(store['louver'][0])
min_temp = store['min_temp']
max_temp = store['max_temp']
curr_temp = min_temp
temp_interval = store['interval']
config = [store['power'], store['modes'], store['fan_speed'], store['swing'], store['louver']]
titles = ['Power', 'Mode', 'Fan', 'Swing', 'Louver']
grid_layout = ObjectProperty()
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.grid_layout.rows = 0
print(self.power, self.mode, self.fan_speed, self.swing, self.louver)
for i in range(len(self.config)):
self.populate_controls(self.config[i], self.titles[i])
def populate_controls(self, config_type, text):
if len(config_type) is not 1:
if config_type != 'not available':
stack_layout = CustomStackLayout()
self.grid_layout.rows += 1
lbl = CustomLabel(text=text, width=self.grid_layout.width, height=self.grid_layout.height*.5)
stack_layout.add_widget(lbl)
for i in range(len(config_type)):
btn = CustomToggleButton(group=text, text=config_type[i], width=40 + len(config_type[i]) * 20,
height=self.grid_layout.height * .5)
if i is 0:
btn.state = 'down'
stack_layout.add_widget(btn)
self.grid_layout.add_widget(stack_layout)
class TestApp(App):
def build(self):
return MainScreen()
if __name__ == '__main__':
TestApp().run()
This is the JSON file:
{
"power": ["off", "on"],
"min_temp": 18,
"max_temp": 32,
"interval": 1,
"modes": ["cool", "fan", "dry"],
"fan_speed": ["auto", "low", "med-low", "med", "med-high", "high"],
"swing": ["off", "auto"],
"louver": ["off", "auto"]
}
I think the easiest fix is to use size_hint. Try changing your CustomLabel and CustomTogglebutton definitions in your kv to:
<CustomToggleButton>:
background_color: hex('#669999')
font_size: self.height*.5
size_hint: 0.1, 0.5
<CustomLabel>:
font_size: self.height * .5
size_hint: 0.1, 0.5
text_size: self.size
halign: 'left'
And you no longer need width and heightspeifications in your Python code for these objects. Also, change CustomStackLayout to:
<CustomStackLayout>:
size_hint_y: 1.0
spacing: 10