I am learning programming in python and working on one simple gaming application in which I need to rotate two rectangles on click on them on single screen but what's happening is when I am clicking on one of them both the rectangles rotate along the origin of that rectangle that is being clicked but this is not the case with another rectangle, in fact its position is not also that that is supposed to be and when clicking on the assigned position(where that rectangle is not present) it gets rotated without rotating both the rectangles. I just need to rotate both the rectangles on clicking independently. It is difficult to explain it so please try to execute the code and find whats happening.
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
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<Stage_2>:
object2: Object2
object3: Object3
Object2:
id: Object2
center: self.rotate_origin
Object3:
id: Object3
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"
root.current = "stage2"
Screen:
name: 'stage2'
Stage_2:
id:s2
''')
class Object2(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 425
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 150
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:
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0,197,68))
Rectangle(pos=self.rect_pos, size=self.rect_size)
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class Object3(Widget):
def __init__(self, *args, **kwargs):
Widget.__init__(self, *args, **kwargs)
self.rect_pos_x = 500
self.rect_pos_y = 250
self.rect_pos = self.rect_pos_x, self.rect_pos_y
self.rect_width = 150
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 2')
with self.canvas:
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(1,255,0))
Rectangle(pos=self.rect_pos, size=self.rect_size)
def rotate(self):
self.canvas.clear()
self.angle += 90
if (self.angle > 315):
self.angle = 225
with self.canvas:
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(0, 255, 100))
Rectangle(pos=self.rect_pos, size=self.rect_size)
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
self.rotate()
print(self.angle)
class Stage_2(Widget):
object2 = ObjectProperty(None)
object3 = ObjectProperty(None)
class Manager(ScreenManager):
pass
sm = Manager()
class ScreensApp(App):
def build(self):
return sm
if __name__ == '__main__':
ScreensApp().run()
If you include PushMatrix()
and PopMatrix()
in your canvas
instructions, then only the current Widget
will be affected. And then, if you adjust the Widget
size
and pos
to that of the Rectangle
, you should get better (but not perfect) collide_point
performance:
with self.canvas:
PushMatrix()
Rotate(origin=self.rotate_origin, angle=self.angle)
Color(rgb=(1,255,0))
Rectangle(pos=self.rect_pos, size=self.rect_size)
PopMatrix()
self.pos = self.rect_pos
self.size = self.rect_size
This needs to be done whenever you use with self.canvas
that involves Rotation
, Scale
, or Translate
. The collide_point()
will still be looking at the Widget
size
and pos
, not the Rectangle
, but at least the centers of the Widget
and its Rectangle
should coincide.