need to rotate each ring of the textinputs separately, but the program rotates all the canvas at the same time. To solve this problem, I defined regions for the collide_point of each ring and also append each ring separately in a list to call them by index in collide_point but they still stick together in rotating!
What am I missing?
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.properties import NumericProperty
from kivy.core.window import Window
import math
kv = '''
<MyLayout>:
Slider:
min : 8
max : 40
on_value : root.slide_it(*args)
<Scat>:
#pos_hint:{"x":0,"y":0}
canvas.before:
PushMatrix
Rotate:
angle: self.angle
origin: self.center
canvas.after:
PopMatrix
<-RotatableTI>:
size_hint: None, None
canvas.before:
PushMatrix
Rotate:
angle: root.angle
axis: 0,0,1
origin: self.center
Color:
rgba: self.background_color
BorderImage:
border: self.border
pos: self.pos
size: self.size
source: self.background_active if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
Color:
rgba:
(self.cursor_color
if self.focus and not self._cursor_blink
else (0, 0, 0, 0))
Rectangle:
pos: self._cursor_visual_pos
size: root.cursor_width, -self._cursor_visual_height
Color:
rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text else self.foreground_color)
canvas.after:
PopMatrix
'''
Builder.load_string(kv)
class RotatableTI(TextInput):
angle = NumericProperty(0)
class Scat(FloatLayout):
#Window.size = (650, 650)
_registry = []
def __init__(self, **kwargs):
super(Scat, self).__init__(**kwargs)
pi = math.pi
txsize_x=50
txsize_y=30
r = 150
for j in range(2,5):
div = 20
for i in range(1,div):
angle = 360.0 / (div - 1) * i
p_x = (Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) *j*r/2)-txsize_x/2
p_y = (Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) *j*r/2)-txsize_y/2
self.add_widget(RotatableTI(text="hi" + str(i), size=(txsize_x, txsize_y), pos=(p_x, p_y), angle=angle))
self._registry.append(self)
angle = NumericProperty(0)
def ring1(self):
#shal we use vector to make a new ring with bigger radius??
center_x=self.center[0]
center_y = self.center[1]
def on_touch_down(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
self.prev_angle = calc if calc > 0 else 360+calc
self.tmp = self.angle
if self.collide_point(*touch.pos):
return super(Scat, self).on_touch_down(touch)
def on_touch_move(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
new_angle = calc if calc > 0 else 360+calc
if self.collide_point(*touch.pos) and 125**2<(touch.x - self.center[0]) ** 2 + (touch.y - self.center[1]) ** 2 < 175**2:
self.angle = self.tmp + (new_angle-self.prev_angle)%360
return super(Scat, self._registry[0]).on_touch_move(touch)
elif self.collide_point(*touch.pos) and 200 ** 2 < (touch.x - self.center[0]) ** 2 + (
touch.y - self.center[1]) ** 2 < 250 ** 2:
self.angle = self.tmp + (new_angle - self.prev_angle) % 360
return super(Scat, self._registry[1]).on_touch_move(touch)
elif self.collide_point(*touch.pos) and 275 ** 2 < (touch.x - self.center[0]) ** 2 + (
touch.y - self.center[1]) ** 2 < 325 ** 2:
self.angle = self.tmp + (new_angle - self.prev_angle) % 360
return super(Scat, self._registry[2]).on_touch_move(touch)
class AslApp(App):
def build(self):
return Scat()
if __name__ == "__main__":
AslApp().run()
Related
Goals of the code below are defining 3 rings of textinputs that can rotate around their center with the mouse separately and the number of each ring’s textinputs changes with a slider.
there are some problems for achieving these goals:
1.after rotating textinputs with the mouse, select each textinput by clicking on them in their apparent new position not working and should click in the starting position of them that is not desirable.
2.need to rotate each ring separately, but the program rotates all rings with each other(regions defined collide_points of each ring but that is not disjoined them).
3.define the center of the rings in the center of the window(currently by scaling the window, the center of the rings will change).
4.bind a slider to each ring to determine the number of textinputs in each ring.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.properties import NumericProperty
from kivy.core.window import Window
import math
from kivy.uix.slider import Slider
kv = '''
<MyLayout>:
Slider:
min : 8
max : 40
on_value : root.slide_it(*args)
<Scat>:
#pos_hint:{"x":0,"y":0}
canvas.before:
PushMatrix
Rotate:
angle: self.angle
origin: self.center
canvas.after:
PopMatrix
<-RotatableTI>:
size_hint: None, None
canvas.before:
PushMatrix
Rotate:
angle: root.angle
axis: 0,0,1
origin: self.center
Color:
rgba: self.background_color
BorderImage:
border: self.border
pos: self.pos
size: self.size
source: self.background_active if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
Color:
rgba:
(self.cursor_color
if self.focus and not self._cursor_blink
else (0, 0, 0, 0))
Rectangle:
pos: self._cursor_visual_pos
size: root.cursor_width, -self._cursor_visual_height
Color:
rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text else self.foreground_color)
canvas.after:
PopMatrix
'''
Builder.load_string(kv)
class RotatableTI(TextInput):
angle = NumericProperty(0)
class Scat(FloatLayout):
Window.size = (650, 650)
def __init__(self, **kwargs):
super(Scat, self).__init__(**kwargs)
pi = math.pi
txsize_x=50
txsize_y=30
r = 150
#txin=[]
for j in range(2,5):
#how to change variable div for each ring with a slider(3 slider for 3rings division)
div = 20 #tried self.div for next 5lines for matching slider code that commented below but not working
for i in range(div):
angle = 360.0 / (div - 1) * i
p_x = (Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) *j*r/2)-txsize_x/2
p_y = (Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) *j*r/2)-txsize_y/2
self.add_widget(RotatableTI(text="hi" + str(i), size=(txsize_x, txsize_y), pos=(p_x, p_y), angle=angle))
#txin.append(self)
# use next five lines of comment for bind slider to number of textinputs in codes above (div), but now works now well
# self.brightnessControl = Slider(min=0, max=100)
# self.add_widget(self.brightnessControl)
# self.brightnessControl.bind(value=self.on_value)
# def on_value(self, instance, division):
# self.div = "% d" % division
angle = NumericProperty(0)
def ring1(self):
#shal we use vector to make a new ring with bigger radius??
pass
def on_touch_down(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
self.prev_angle = calc if calc > 0 else 360+calc
self.tmp = self.angle
if self.collide_point(*touch.pos):
return super(Scat, self).on_touch_down(touch)
def on_touch_move(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
new_angle = calc if calc > 0 else 360+calc
if self.collide_point(*touch.pos) and 125**2<(touch.x - self.center[0]) ** 2 + (touch.y - self.center[1]) ** 2 < 175**2:
self.angle = self.tmp + (new_angle-self.prev_angle)%360
return super(Scat, self).on_touch_move(touch)
elif self.collide_point(*touch.pos) and 200 ** 2 < (touch.x - self.center[0]) ** 2 + (
touch.y - self.center[1]) ** 2 < 250 ** 2:
self.angle = self.tmp + (new_angle - self.prev_angle) % 360
return super(Scat, self).on_touch_move(touch)
elif self.collide_point(*touch.pos) and 275 ** 2 < (touch.x - self.center[0]) ** 2 + (
touch.y - self.center[1]) ** 2 < 325 ** 2:
self.angle = self.tmp + (new_angle - self.prev_angle) % 360
return super(Scat, self).on_touch_move(touch)
class AslApp(App):
def build(self):
return Scat()
if __name__ == "__main__":
AslApp().run()
I am working on one gaming app in which I need the ball widget to get deflected at the angle of 90 to the direction of movement by the rectangle widget after getting collided. In the below code the ball is doing what I said above but it is getting deflected some distance before colliding the rectangle. It would due to the functioning of collide_widget() in the code, Please help to solve this issue!
from kivy.app import App
from kivy.graphics import Rotate, Rectangle, Ellipse, Color
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, CardTransition
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, NumericProperty, ReferenceListProperty, ListProperty,
DictProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.graphics.context_instructions import PopMatrix, PushMatrix
Builder.load_string('''
<PongBall>:
size: 50, 50
canvas:
Color:
rgba: 0,0,1,1
Ellipse:
pos: self.pos
size: self.size
<Game>:
ball: pong_ball
object: Object
FloatLayout:
Button:
pos_hint:{"x":2.6,"y":0}
size_hint: 3, 1
text:"Throw"
background_color: 2,1,190,1
border: 30,30,30,30
on_release:
root.start()
Button:
pos_hint:{'x':7.3, 'y':5.3}
size_hint: 0.5,0.5
text:'restart'
on_release:
root.serve_ball()
PongBall:
id: pong_ball
center: self.center
Object:
id: Object
center: self.rotate_origin
<Game1>:
ball: pong_ball
object1: Object1
object2: Object2
FloatLayout:
Button:
pos_hint:{"x":2.6,"y":0}
size_hint: 3, 1
text:"Throw"
background_color: 2,1,190,1
border: 30,30,30,30
on_release:
root.start()
Button:
pos_hint:{'x':7.3, 'y':5.3}
size_hint: 0.5,0.5
text:'restart'
on_release:
root.serve_ball()
PongBall:
id: pong_ball
center: self.center
Object1:
id: Object1
center: self.rotate_origin
Object2:
id: Object2
center: self.rotate_origin
<Manager>:
id: screen_manager
Screen:
name:"P"
FloatLayout:
Button:
pos_hint:{"x":0.2,"y":0.05}
size_hint: 0.6, 0.2
font_size: (root.width**2 + root.height**2) / 13**4
text: "Play"
background_color: 255,0,1,1
on_release:
root.transition.direction = "up";s3.serve_ball()
root.current = "again"
Screen:
name: 'again'
Game1:
id:s3
''')
class Object(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 370
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 200
self.rect_height = 30
self.rect_size = self.rect_width, self.rect_height
self.rotate_origin_x = self.rect_pos_x + self.rect_width / 2
self.rotate_origin_y = self.rect_pos_y + self.rect_height / 2
self.rotate_origin = self.rotate_origin_x, self.rotate_origin_y
self.angle = 135
print('rect 1')
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0,197,68))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def deflect_ball(self, ball):
if self.collide_widget(ball):
if not ball.collided:
vx, vy = ball.velocity
if self.angle == 135:
ball.velocity = Vector(-vx, vy).rotate(90)
if self.angle == 225:
ball.velocity = Vector(-vx, vy).rotate(270)
if self.angle == 315:
ball.velocity = Vector(-vx, vy).rotate(90)
ball.collided = True
else:
ball.collided = False
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
collided = DictProperty(False)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class Game(Widget):
ball = ObjectProperty(None)
object = ObjectProperty(None)
def start(self):
Clock.schedule_interval(self.update, 1.0 / 60.0)
def serve_ball(self, vel=(5, 0)):
Clock.unschedule(self.update)
self.ball.center = 40, 380
self.ball.velocity = vel
def update(self, dt):
self.ball.move()
self.object.deflect_ball(self.ball)
if (self.ball.y < self.y+50) or self.ball.y > 500:
self.ball.velocity_y = 0
Clock.unschedule(self.update)
print('tested')
self.serve_ball()
sm.current= 'again'
class Object1(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 400
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 200
self.rect_height = 30
self.rect_size = self.rect_width, self.rect_height
self.rotate_origin_x = self.rect_pos_x + self.rect_width / 2
self.rotate_origin_y = self.rect_pos_y + self.rect_height / 2
self.rotate_origin = self.rotate_origin_x, self.rotate_origin_y
self.angle = 135
print('rect 1')
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0,197,68))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def deflect_ball(self, ball):
if self.collide_widget(ball):
if not ball.collided[self]:
vx, vy = ball.velocity
if self.angle == 135:
ball.velocity = Vector(-vx, vy).rotate(90)
if self.angle == 225:
ball.velocity = Vector(-vx, vy).rotate(270)
if self.angle == 315:
ball.velocity = Vector(-vx, vy).rotate(90)
ball.collided[self] = True
else:
ball.collided[self] = False
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class Object2(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 170
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 200
self.rect_height = 30
self.rect_size = self.rect_width, self.rect_height
self.rotate_origin_x = self.rect_pos_x + self.rect_width / 2
self.rotate_origin_y = self.rect_pos_y + self.rect_height / 2
self.rotate_origin = self.rotate_origin_x, self.rotate_origin_y
self.angle = 135
print('rect 1')
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0,197,68))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
def deflect_ball(self, ball):
if self.collide_widget(ball):
if not ball.collided[self]:
vx, vy = ball.velocity
if self.angle == 135:
ball.velocity = Vector(-vx, vy).rotate(90)
if self.angle == 225:
ball.velocity = Vector(-vx, vy).rotate(270)
if self.angle == 315:
ball.velocity = Vector(-vx, vy).rotate(90)
ball.collided[self] = True
else:
ball.collided[self] = False
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class Game1(Widget):
ball = ObjectProperty(None)
object1 = ObjectProperty(None)
object2 = ObjectProperty(None)
def start(self):
Clock.schedule_interval(self.update, 1.0 / 60.0)
def serve_ball(self, vel=(5, 0)):
Clock.unschedule(self.update)
self.ball.center = 40, 380
self.ball.velocity = vel
def update(self, dt):
self.ball.move()
self.object1.deflect_ball(self.ball)
self.object2.deflect_ball(self.ball)
if (self.ball.y < self.y+50) or self.ball.x <0:
self.ball.velocity_y = 0
Clock.unschedule(self.update)
print('tested')
self.serve_ball()
class Manager(ScreenManager):
pass
sm = Manager()
class ScreensApp(App):
def build(self):
return sm
if __name__ == '__main__':
ScreensApp().run()
Because the collide_widget() method compares pos and size of the involved Widgets, the canvas drawing instructions have no effect on collision detection. So, I think you need to define your own method to detect a collision. Here is my attempt at such a method:
def collide_ball(self, ball):
# get vector from center of rect to the ball
to_ball = Vector((ball.x - self.rotate_origin_x), (ball.y - self.rotate_origin_y))
# get x and y coordinates of above vector in rotated system
x = to_ball.dot(self.rot_x_dir) # along rect width
y = to_ball.dot(self.rot_y_dir) # along rect height
# test for collision
if x < -self.rect_width/2 - ball.size[0]/2:
return False
if x > self.rect_width/2 + ball.size[0]/2:
return False
if y < -self.rect_height/2 - ball.size[1]/2:
return False
if y > self.rect_height/2 + ball.size[1]/2:
return False
return True
This method should appear in each Object.
This requires the definition of self.rot_x_dir and self.rot__dir, which represent a coordinate system that is rotated with the Object1 or Object2 rectangle. These must be redefined wherever the rotation angle for the Object is changed. For example, in the Object1.__init__():
self.angle = 135
self.rot_x_dir = Vector(1,0).rotate(self.angle)
self.rot_y_dir = Vector(0,1).rotate(self.angle)
same code goes in the Object2.__init__(). Similarly, in the rotate() method:
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
self.rot_x_dir = Vector(1,0).rotate(self.angle)
self.rot_y_dir = Vector(0,1).rotate(self.angle)
with self.canvas:
PushMatrix()
self.rot = Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
Then, wherever you now use
self.collide_widget(ball)
replace it with:
self.collide_ball(ball)
Also, in your 'kv' adjust the drawing of the PongBall:
<PongBall>:
size: 50, 50
canvas:
Color:
rgba: 0,0,1,1
Ellipse:
# adjust Ellipse position to center it
pos: self.x - self.size[0]/2, self.y - self.size[1]/2
size: self.size
If your run it once the ball is about to stop it starts skipping up and down a little bit and disappears through the floor.
So i was following the kivy tutorial for the pong game and half way through i thought why not make the ball have gravity...i kind of figured that out though I don't know wether it's good code or not but that's not my problem. I already compared it to some other code basically doing the same and didn't find any differences. Could somebody tell me what i have done wrong? (Sorry i had to paste all my code in here but i don't know where the problem is...)
import kivy
kivy.require("1.10.1")
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 PongBall(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
def update_speed(self):
self.velocity[1] = self.velocity[1] - 15/60
self.pos = Vector(*self.velocity) + self.pos
class PongGame(Widget):
ball = ObjectProperty(None)
def serve_ball(self):
self.ball.center = self.center
self.ball.velocity = Vector(0, 0)
def update(self, dt):
self.ball.update_speed()
if (self.ball.y < 0) or (self.ball.top > self.height):
self.ball.velocity_y *= -1
if (self.ball.x < 0) or (self.ball.right > self.width):
self.serve_ball()
class PongApp(App):
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0/60.0)
return game
if __name__ == '__main__':
PongApp().run()
This is my kv file:
#:kivy 1.10.1
<PongBall>:
size: 50, 50
canvas:
Ellipse:
pos: self.pos
size: self.size
<PongGame>:
ball: pong_ball
canvas:
Rectangle:
pos: self.center_x - 5, 0
size: 10, self.height
Label:
font_size: 70
center_x: root.width / 4
top: root.height * 9 / 10
text: "0"
Label:
font_size: 70
center_x: root.width * 3 / 4
top: root.height * 9 / 10
text: str(pong_ball.velocity[1])
PongBall:
id: pong_ball
center: self.parent.center
I want the ball to slow down until it lays on the ground and doesn't move.
this is just a common problem with floats ...
just in your update speed function do something like
if velocity <= 1e-6: # some really small number
velocity = 0.0
its also probably a good idea to fix your y position in your move function
if (self.ball.y < 0) or (self.ball.top > self.height):
self.ball.y = 0.1
self.ball.velocity_y *= -1
I need to change orientation to vertical, but it does not work the same way as BoxLayout. There is also no information about this in the Kivy official documentation. In addition, is there any way to change the page by swiping from any place on the screen and not only the border?
Python:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("final.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
Kivy:
ScreenManagement:
MainScreen:
<MainScreen>:
canvas:
Rectangle:
source: "nakedman.jpg"
pos: self.pos
size: self.size
name: "main"
PageLayout:
orientation: "vertical"
BoxLayout:
Button:
text: "Button1"
Button:
text: "Button2"
BoxLayout:
Button:
text: "Button3"
Button:
text: "Button4"
PageLayout does not have the orientation attribute, so you have to build everything, in this case use the source code of PageLayout to obtain this new code:
__all__ = ('PageLayoutVertical', )
from kivy.uix.layout import Layout
from kivy.properties import NumericProperty, DictProperty
from kivy.animation import Animation
class PageLayoutVertical(Layout):
'''PageLayout class. See module documentation for more information.
'''
page = NumericProperty(0)
'''The currently displayed page.
:data:`page` is a :class:`~kivy.properties.NumericProperty` and defaults
to 0.
'''
border = NumericProperty('50dp')
'''The width of the border around the current page used to display
the previous/next page swipe areas when needed.
:data:`border` is a :class:`~kivy.properties.NumericProperty` and
defaults to 50dp.
'''
swipe_threshold = NumericProperty(.5)
'''The thresold used to trigger swipes as percentage of the widget
size.
:data:`swipe_threshold` is a :class:`~kivy.properties.NumericProperty`
and defaults to .5.
'''
anim_kwargs = DictProperty({'d': .5, 't': 'in_quad'})
'''The animation kwargs used to construct the animation
:data:`anim_kwargs` is a :class:`~kivy.properties.DictProperty`
and defaults to {'d': .5, 't': 'in_quad'}.
.. versionadded:: 1.11.0
'''
def __init__(self, **kwargs):
super(PageLayoutVertical, self).__init__(**kwargs)
trigger = self._trigger_layout
fbind = self.fbind
fbind('border', trigger)
fbind('page', trigger)
fbind('parent', trigger)
fbind('children', trigger)
fbind('size', trigger)
fbind('pos', trigger)
def do_layout(self, *largs):
l_children = len(self.children) - 1
w = self.width
x_parent, y_parent = self.pos
p = self.page
border = self.border
half_border = border / 2.
top = self.top
height = self.height - border
for i, c in enumerate(reversed(self.children)):
if i < p:
y = y_parent
elif i == p:
if not p: # it's first page
y = y_parent
elif p != l_children: # not first, but there are post pages
y = y_parent + half_border
else: # not first and there are no post pages
y = y_parent + border
elif i == p + 1:
if not p: # second page - no left margin
y = top - border
else: # there's already a left margin
y = top - half_border
else:
y = top
c.width = w
c.height = height
Animation(
x=x_parent,
y=y,
**self.anim_kwargs).start(c)
def on_touch_down(self, touch):
if (
self.disabled or
not self.collide_point(*touch.pos) or
not self.children
):
return
page = self.children[-self.page - 1]
if self.y <= touch.y < page.y:
touch.ud['page'] = 'previous'
touch.grab(self)
return True
elif page.top <= touch.y < self.top:
touch.ud['page'] = 'next'
touch.grab(self)
return True
return page.on_touch_down(touch)
def on_touch_move(self, touch):
if touch.grab_current != self:
return
p = self.page
border = self.border
half_border = border / 2.
page = self.children[-p - 1]
if touch.ud['page'] == 'previous':
# move next page upto right edge
if p < len(self.children) - 1:
self.children[-p - 2].y = min(
self.top - self.border * (1 - (touch.sy - touch.osy)),
self.top)
# move current page until edge hits the right border
if p >= 1:
b_right = half_border if p > 1 else border
b_left = half_border if p < len(self.children) - 1 else border
self.children[-p - 1].y = max(min(
self.y + b_left + (touch.y - touch.oy),
self.top - b_right),
self.y + b_left)
# move previous page left edge upto left border
if p > 1:
self.children[-p].y = min(
self.y + half_border * (touch.sy - touch.osy),
self.y + half_border)
elif touch.ud['page'] == 'next':
# move current page upto left edge
if p >= 1:
self.children[-p - 1].y = max(
self.y + half_border * (1 - (touch.osy - touch.sy)),
self.y)
# move next page until its edge hit the left border
if p < len(self.children) - 1:
b_right = half_border if p >= 1 else border
b_left = half_border if p < len(self.children) - 2 else border
self.children[-p - 2].y = min(max(
self.top - b_right + (touch.y - touch.oy),
self.y + b_left),
self.top - b_right)
# move second next page upto right border
if p < len(self.children) - 2:
self.children[-p - 3].y = max(
self.top + half_border * (touch.sy - touch.osy),
self.top - half_border)
return page.on_touch_move(touch)
def on_touch_up(self, touch):
if touch.grab_current == self:
if (
touch.ud['page'] == 'previous' and
abs(touch.y - touch.oy) / self.height > self.swipe_threshold
):
self.page -= 1
elif (
touch.ud['page'] == 'next' and
abs(touch.y - touch.oy) / self.height > self.swipe_threshold
):
self.page += 1
else:
self._trigger_layout()
touch.ungrab(self)
if len(self.children) > 1:
return self.children[-self.page + 1].on_touch_up(touch)
if __name__ == '__main__':
from kivy.base import runTouchApp
from kivy.uix.button import Button
pl = PageLayoutVertical()
for i in range(1, 10):
b = Button(text='page%s' % i)
pl.add_widget(b)
runTouchApp(pl)
I'm trying to make an kivy app with starting menu, but I can't display my Pong Game on the second screen. How should I refer to the game to make it visible? I tried and searched but can't find anything. I'm 100% sure that PongGame work corectly, I just can't display it. It would be great if someone could show me how to do it corectly.
Main.py:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.uix.popup import Popup
from kivy.uix.label import Label
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 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))
if self.player1.score == 10:
popup = Popup(title='Test popup', content=Label(text='Hello world'), auto_dismiss=False)
return popup
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 ScreenThree(Screen):
pass
class ScreenTwo(Screen):
pass
class ScreenOne(Screen):
pass
class Manager(ScreenManager):
screen_one = ObjectProperty(None)
screen_two = ObjectProperty(None)
screen_three = ObjectProperty(None)
class ScreensApp(App):
def build(self):
m = Manager(transition=WipeTransition())
return m
if __name__ == '__main__':
ScreensApp().run()
screen.kv:
<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
<ScreenOne>:
Button:
text: "Screen 1 >> Screen 2"
on_press: root.manager.current = 'screen2'
<ScreenTwo>:
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0 / 60.0)
return game
<ScreenThree>:
Button:
text: "Screen 3 >> Screen 1"
on_press: root.manager.current = 'screen1'
<Manager>:
id: screen_manager
screen_one: screen_one
screen_two: screen_two
screen_three: screen_three
ScreenOne:
id: screen_one
name: 'screen1'
manager: screen_manager
ScreenTwo:
id: screen_two
name: 'screen2'
manager: screen_manager
ScreenThree:
id: screen_three
name: 'screen3'
manager: screen_manager
Well! there were a lot of errors in your program and I had to make ton's of improvement. (I understand it as you are beginner)
First of all, please read complete kivy language documentation, as I can clearly see that you directly started with coding without grasping the basics.
You may make couple of good games but in the long run you will face such problems which can't be solved without clear concepts.
And unfortunately you won't be able to discover the true power of kivy. :)
You might also wanna do revision of your python concepts.
Some improvements aren't worth mentioning but were important, you will get an idea when you read the code.
Improvement 1:
An application can be built if you return a widget on build(), or if you set self.root.(But you cannot make the application again n again)
as you did here:
<ScreenTwo>:
def build(self):
game = PongGame()
game.serve_ball()
Clock.schedule_interval(game.update, 1.0 / 60.0)
return game
Improvement 2:
As you click on button play ping pong which is of screen game. your game starts with serve of ball.
on_release: root.current = 'game';game.serve_ball()
(for knowledge)
If you still get black screen you might want to check the name of kivy file, for that you could either go to kivy documentation or this link
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 ScreensApp(App):
def build(self):
self.load_kv('t6.kv')
return Manager(transition=WipeTransition())
if __name__ == '__main__':
ScreensApp().run()
Here is the kv file.
<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