Why is collide_widget not working here? - python

I am wondering why my 'collide_with_hero' method does not seem to be working? Is there something wrong with my Npcs class?
I am just trying to detect when widgets collide (the hero and the tree widget), I stripped out all the additional code in the method, and I am at the point now where I am just simply trying to detect collision and print something if True. When I run the game and walk my hero character into the tree, nothing prints, nothing happens.
I call self.tree.collide_with_widget in the build. Any advice on what I am doing wrong here?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.audio import SoundLoader
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import FallOutTransition
gamelayout = RelativeLayout(size=(300, 300))
bglayout = RelativeLayout()
class Game(Screen):
pass
class Bg(Image):
def __init__(self, **kwargs):
super(Bg, self).__init__(**kwargs)
self.allow_stretch = True
self.size_hint = (None, None)
self.size = (1440, 1440)
class Npcs(Image):
def __init__(self, **kwargs):
super(Npcs, self).__init__(**kwargs)
def collide_with_hero(self, hero):
if self.collide_widget(hero):
print "you ran into a tree"
#dir1 = self.hero.x - self.x
#if self.x < self.hero.x:
# self.hero.x = self.x + dir1
class MoveableImage(Image):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
self._keyboard.bind(on_key_up=self.on_keyboard_up)
self.size_hint = (.11, .11)
self.y = (Window.height/2.1)
self.app = App.get_running_app()
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.source = 'selectionscreen/left.zip'
self.anim_delay=.20
if self.x < (Window.width * .25):
bglayout.x += 4
else:
self.x -= 6
elif keycode[1] == 'right':
self.source ='selectionscreen/right.zip'
self.anim_delay=.20
if self.x > (Window.width * .70):
bglayout.x -= 4
else:
self.x += 6
elif keycode[1] == 'down':
self.source ='selectionscreen/right.zip'
self.anim_delay=.20
if self.y < (Window.height * .25):
bglayout.y += 4
else:
self.y -= 6
elif keycode[1] == 'up':
self.source = 'selectionscreen/back.zip'
self.anim_delay=.1
if self.y > (Window.height * .70):
bglayout.y -= 4
else:
self.y += 6
else:
return False
return True
def on_keyboard_up(self, keyboard, keycode):
if keycode[1] == 'left':
self.source = 'selectionscreen/left1.png'
elif keycode[1] == 'right':
self.source ='selectionscreen/right1.png'
elif keycode[1] == 'down':
self.source ='selectionscreen/right1.png'
elif keycode[1] == 'up':
self.source ='selectionscreen/back2.png'
else:
return False
return True
class gameApp(App):
def build(self):
global sm
sm = ScreenManager()
game = Game(name='game')
sm.add_widget(game)
hero = MoveableImage(source='selectionscreen/right1.png', pos=(75, 40))
self.tree = Npcs(source='selectionscreen/tree.zip', pos=(100, 200))
self.tree.collide_with_hero(hero)
self.background=Bg(source='selectionscreen/background9.png')
#add widgets to bglayout
bglayout.add_widget(self.background)
bglayout.add_widget(self.tree)
#add bglayout and moveable hero to gamelayout
gamelayout.add_widget(bglayout)
gamelayout.add_widget(hero)
game.add_widget(gamelayout)
return sm
if __name__ == '__main__':
gameApp().run()

You need a main game loop to check for collision after some interval in time or on a keypress event. You can take a look at the Pong example here: http://kivy.org/docs/tutorials/pong.html to get an idea about how to achieve that.
More specifically start reading from this section: http://kivy.org/docs/tutorials/pong.html#adding-ball-animation.
Clock.schedule_interval(game.update, 1.0/60.0)
It uses Clock.schedule_interval to schedule a main loop function called "update".
def update(self, dt):
self.ball.move()
#bounce off top and bottom
if (self.ball.y < 0) or (self.ball.top > self.height):
self.ball.velocity_y *= -1
#bounce off left and right
if (self.ball.x < 0) or (self.ball.right > self.width):
self.ball.velocity_x *= -1
You will need to write the collision detection code in a function like that. If your game involves more complex Physics simulation then you may consider using a library like http://box2d.org/. It will manage all the collisions and stuff for you.

First, you made self.tree an Image, but this doesn't have a collide_with_hero method. You need to make it an instance of the new class you defined, Npcs.
Second, you didn't call the collide_with_hero method. You need to do self.tree.collide_with_hero(hero) to actually call it including passing your hero as an argument to the function.

Related

How to handle multiple keyboard inputs in kivy?

so im developing this game, which is a platformer, so im working on the movements now, the problem is:
i can move the player to the left and right side, i can also jump, however i can't move and jump at the same time, like, while im moving forward i want to be able to jump forward and that would require me to press the forward and the up buttons.
i've tried many ways to get this but with no success and i haven't found this issue googling around, so... here's the minimal code to help things out.
the issue is the player either jump or move, it doesn't do both when i press the up and forward keys.
Main.py
from kivy.core.window import Window
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.floatlayout import MDFloatLayout
from kivy.properties import Clock
from Player import PlayerImage
class LevelOneLayout(MDFloatLayout):
pass
class LevelOne(MDScreen):
from PlayerAction import _keyboard_closed, _on_keyboard_down, _on_keyboard_up
gravity_force = 1800
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down = self._on_keyboard_down)
self._keyboard.bind(on_key_up = self._on_keyboard_up)
Clock.schedule_once(self.setup, 1/60)
def setup(self, dt):
self.player_image = PlayerImage()
self.add_widget(self.player_image)
Clock.schedule_interval(self.game_gravity, 1/30)
def game_gravity(self, dt):
if self.player_image.on_air:
self.player_image.player_gravity_vel -= self.gravity_force * 1/30
self.player_image.y += self.player_image.player_gravity_vel * 1/30
if self.player_image.y <= 60:
self.player_image.y = 60
self.player_image.player_gravity_vel = 0
self.player_image.on_air = False
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Red"
return
MainApp().run()
Main.kv
LevelOne:
LevelOneLayout:
<LevelOneLayout>:
<PlayerImage>:
source: "player_77x100.png"
size_hint: None, None
size: "77dp", "100dp"
x: "0dp"
y: "50dp"
Player.py
from kivy.uix.image import Image
from kivy.animation import Animation
from kivymd.uix.floatlayout import MDFloatLayout
class PlayerImage(Image):
texture_side = "right"
def __init__(self):
super().__init__()
self.velx = 20
self.player_gravity_vel = 0
self.on_air = False
def move_left(self, state, *args):
if state:
self.x -= self.velx
self.texture_left()
self.forced_dash = False
else:
return None
def move_right(self, state, *args):
if state:
self.x += self.velx
self.texture_right()
self.forced_dash = False
else:
return None
def jump(self, state, *args):
if not self.on_air and state:
self.player_gravity_vel = 830
self.on_air = True
else:
return None
def texture_left(self):
if self.texture.tex_coords[0] == 0:
self.texture.flip_horizontal()
self.texture.ask_update(self.update_texture)
self.texture_side = "left"
def texture_right(self):
if self.texture.tex_coords[0] == 1:
self.texture.flip_horizontal()
self.texture.ask_update(self.update_texture)
self.texture_side = "right"
def update_texture(self, texture):
self.texture = None
self.texture = texture
PlayerAction.py
key_state = True
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down = self._on_keyboard_down)
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, *args):
if keycode[1] == "up":
self.player_image.jump(key_state)
if keycode[1] == "left":
self.player_image.move_left(key_state)
elif keycode[1] == "right":
self.player_image.move_right(key_state)
return True
def _on_keyboard_up(self, keyboard, keycode, *args):
key_state = False
if keycode[1] == "up":
self.player_image.jump(key_state)
if keycode[1] == "left":
self.player_image.move_left(key_state)
elif keycode[1] == "right":
self.player_image.move_right(key_state)
return True
so for an example that manages multiple key presses i recommend this link:
https://groups.google.com/g/kivy-users/c/b0Qmv160GBk
which is the answer to this question i made in the kivy group support, so i've changed a bit the code to suit my code and with Mr.inclements help i did this:
i've put the changes in blockquotes.
Main.py file:
from kivy.core.window import Window
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivymd.uix.floatlayout import MDFloatLayout
from kivy.properties import Clock
from Player import PlayerImage
class LevelOneLayout(MDFloatLayout):
pass
class LevelOne(MDScreen):
from PlayerAction import _keyboard_closed, _on_keyboard_down, _on_keyboard_up, """process_keys"""
gravity_force = 1800
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down = self._on_keyboard_down)
self._keyboard.bind(on_key_up = self._on_keyboard_up)
Clock.schedule_once(self.setup, 1/60)
def setup(self, dt):
self.player_image = PlayerImage()
self.add_widget(self.player_image)
Clock.schedule_interval(self.game_gravity, 1/30)
"""Clock.schedule_interval(self.process_keys, 1/30)"""
def game_gravity(self, dt):
if self.player_image.on_air:
self.player_image.player_gravity_vel -= self.gravity_force * 1/30
self.player_image.y += self.player_image.player_gravity_vel * 1/30
if self.player_image.y <= 60:
self.player_image.y = 60
self.player_image.player_gravity_vel = 0
self.player_image.on_air = False
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Red"
return
MainApp().run()
PlayerAction.py File:
"""pressed_keys = set()"""
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down = self._on_keyboard_down)
"""self._keyboard.unbind(on_key_up = self._on_keyboard_up)"""
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, *args):
"""pressed_keys.add(keycode[1])"""
return True
def _on_keyboard_up(self, keyboard, keycode, *args):
"""pressed_keys.remove(keycode[1])"""
return True
"""
def process_keys(self, dt):
if pressed_keys.issuperset({'up', 'right'}):
self.player_image.jump()
self.player_image.move_right()
elif pressed_keys.issuperset({'up', 'left'}):
self.player_image.jump()
self.player_image.move_left()
elif pressed_keys.issuperset({'left', 'up'}):
self.player_image.move_left()
self.player_image.up()
elif pressed_keys.issuperset({'right', 'up'}):
self.player_image.move_right()
self.player_image.up()
elif pressed_keys.issuperset({'up'}):
self.player_image.jump()
elif pressed_keys.issuperset({'left'}):
self.player_image.move_left()
elif pressed_keys.issuperset({'right'}):
self.player_image.move_right()
"""
Player.py file:
in the player.py file i just deleted the "state" parameter from the "jump", "move_left" and "move_right" methods, since i've deleted the "key_state" variable from the PlayerAction.py file, i wouldn't need the "state" parameter in here.
Notice that the multiple key presses example provided in the kivy support group doesnt use a Clock to call the "process_key" method, instead it just calls from the "_on_keyboard_down" method, however doing this way still makes you feel like the second key is overriding the first, so i've tried using here Mr.inclement's answer by calling the "process_key" method using the Clock, and it works. that it.

How to zoom on a particular point with Kivy in python

So I need to create an interactive game map for other players. They could add some markers on it locally.
I imported the image of the map and saw a stackoverflow subject with someone having the same problem. I got the solution but it's zooming at the center of the picture.
It's a very large picture so i need to make the zoom possible on the cursor of the mouse.
Here's the code I've already made :
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.scatter import Scatter
from kivy.core.window import Window
from kivy.graphics.transformation import Matrix
from kivy.lang import Builder
Builder.load_file('map.kv')
class Zoom(ScatterLayout):
def on_touch_down(self, touch):
x, y = touch.x, touch.y
self.prev_x = touch.x
self.prev_y = touch.y
if touch.is_mouse_scrolling:
if touch.button == 'scrolldown':
print('down')
## zoom in
if self.scale < 10:
self.scale = self.scale * 1.1
elif touch.button == 'scrollup':
print('up') ## zoom out
if self.scale > 1:
self.scale = self.scale * 0.9
# if the touch isn't on the widget we do nothing
if not self.do_collide_after_children:
if not self.collide_point(x, y):
return False
if 'multitouch_sim' in touch.profile:
touch.multitouch_sim = True
# grab the touch so we get all it later move events for sure
self._bring_to_front(touch)
touch.grab(self)
self._touches.append(touch)
self._last_touch_pos[touch] = touch.pos
return True
class Main_app(BoxLayout):
pass
class Stacked(App):
def build(self):
Window.clearcolor = (1, 1, 1, 1)
Window.size = (1000, 700)
Seems like that should be an option for Scatter and ScatterPlane, but it isn't. Here is a hack I have used to accomplish what you asked about:
class MyScatterPlane(ScatterPlane):
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
if touch.is_mouse_scrolling:
if touch.button == 'scrolldown':
mat = Matrix().scale(.9, .9, .9)
self.apply_transform(mat, anchor=touch.pos)
elif touch.button == 'scrollup':
mat = Matrix().scale(1.1, 1.1, 1.1)
self.apply_transform(mat, anchor=touch.pos)
return super().on_touch_up(touch)
This is an extension of ScatterPlane, but it is not extensively tested. Use at your own risk.

How to update the size of the parent widget from the size of the children in Kivy?

This snippet that runs on Kivy for Python draws some rectangles (Boxes) as child widgets of a parent one (RootWidget).
By pressing ALT + D you create another box (added to the RootWidget).
I'm trying to implement a touch and drag behavior on the parent widget so that it moves all the child boxes together when they are dragged with the mouse.
However, the on_touch_down method (see self.collide_point(*touch.pos)) just gets the position of the original child widget (the one created by default) but not of the newly created ones.
Why? Is there a way to update the size of the parent so that it gets grabbed when a box other than the first is touched?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Ellipse, Color, Rectangle, Line
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import NumericProperty, ListProperty
from random import randint
Builder.load_string('''
<Box>:
canvas:
Color:
rgba: .1, .1, 1, .9
Line:
width: 2.
rectangle: (self.x, self.y, self.width, self.height)
''')
class Tree(Widget):
pass
class Node(Widget):
pass
class Box(Widget):
def __init__(self, **kwargs):
super(Box, self).__init__(**kwargs)
self.size = [500, 300]
self.height = self.size[1]
self.width = self.size[0]
self.pos = [500,200]
# bind change of pos to redraw
self.bind(pos=self.redraw, size=self.redraw)
def redraw(self, *args):
# compute head and sisters' positions
self.x = self.pos[0]
self.y = self.pos[1]
#self.height = self.size[0]
#self.width = self.size[1]
class Branches(Widget):
pass
class Terbranch(Widget):
pass
class RootWidget(Widget):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
for i in range(2):
self.add_widget(Box())
self._keyboard = Window.request_keyboard(
self._keyboard_closed, self, 'text')
if self._keyboard.widget:
# If it exists, this widget is a VKeyboard object which you can use
# to change the keyboard layout.
pass
self._keyboard.bind(on_key_down=self._on_keyboard_down)
self.bind(pos=self.redraw, size=self.redraw)
def redraw (self, *args):
pass
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
# if the touch collides with our widget, let's grab it
touch.grab(self)
#print ('touched')
# and accept the touch.
return True
return super(RootWidget, self).on_touch_down(touch)
def on_touch_up(self, touch):
# check if it's a grabbed touch event
if touch.grab_current is self:
# don't forget to ungrab ourself, or you might have side effects
touch.ungrab(self)
# and accept the last up
return True
return super(RootWidget, self).on_touch_up(touch)
def on_touch_move(self, touch):
# check if it's a grabbed touch event
if touch.grab_current is self:
#self.pos = touch.pos
self.pos[0] += touch.dx
self.pos[1] += touch.dy
#redraw moved children
for child in self.children:
child.pos[0] += touch.dx
child.pos[1] += touch.dy
child.redraw()
# and accept the last move
return True
return super(RootWidget, self).on_touch_move(touch)
def _keyboard_closed(self):
print('My keyboard have been closed!')
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
#print('The key', keycode, 'have been pressed')
#print(' - text is %r' % text)
#print(' - modifiers are %r' % modifiers)
# Keycode is composed of an integer + a string
# If we hit escape, release the keyboard
if keycode[1] == 'escape':
keyboard.release()
elif keycode[1] == 'd' and modifiers[0] == 'alt':
newbox = Box()
self.add_widget(newbox)
# Return True to accept the key. Otherwise, it will be used by
# the system.
return True
def update(self, dt):
pass
class MyApp(App):
def build(self):
rw = RootWidget()
#Clock.schedule_interval(rw.update, 0.2)
return rw
if __name__ == "__main__":
MyApp().run()
Not sure I understand your question completely, but in your on_touch_move method you are moving all the child Box instances. But you are also changing the pos of the RootWidget itself. Since the RootWidget is the root window of the App, changing its pos property doesn't have any visual effect. However, that change affects the self.collide_point method (it uses pos and size to check for collision). So, if I understand your question, you just need to eliminate changing the pos of the RootWidget:
def on_touch_move(self, touch):
# check if it's a grabbed touch event
if touch.grab_current is self:
#self.pos = touch.pos
# comment out the next two lines
#self.pos[0] += touch.dx
#self.pos[1] += touch.dy
#redraw moved children
for child in self.children:
child.pos[0] += touch.dx
child.pos[1] += touch.dy
child.redraw()
# and accept the last move
return True

kivy image collider size way too big

What I tried to do:
I wanted my program to print a message when it collides with the sprite in the middle.
Problem:
It doesn't stop printing that it collided. I looked into it with pdb and it says that the Player Sprite is the size of the whole screen, which is weird because I set the image size to 32px by 32px.
What it looks like
Code and Sprites mentioned
Link to mentioned block
Link to mentioned sprite
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
import random
import time
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
#############################################################################
class Collider(Image):
pass
#############################################################################
root = FloatLayout()
class GameScreen(Screen):
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.wimg = Basic(size = (32,32), source='sprite.png', pos=(270,-120))
self.block = Collider(size = (32,32), source = 'block.png')
def playy(self):
root.add_widget(self.wimg)
Clock.schedule_interval(self.wimg.update, 1.0 / 60.0)
def worldgen1(self):
self.add_widget(root)
root.add_widget(self.block)
def on_enter(self):
self.worldgen1()
self.playy()
#############################################################################
class Basic(Image):
pFrame = 0
def __init__(self, **kwargs):
super(Basic, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.x -= 10
elif keycode[1] == 'right':
self.x += 10
elif keycode[1] == 'up':
self.y += 10
elif keycode[1] == 'down':
self.y -= 10
else:
return False
return True
def update(self, dt):
self.pFrame += 1
if self.parent.parent.block.collide_widget(self.parent.parent.wimg):
print ("collide with", self.parent.parent.block)
#############################################################################
class MeinApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(GameScreen(name='gameplay'))
return sm
if __name__ == '__main__':
MeinApp().run()
In this case the problem is that FloatLayout uses the size_hint to set the size of the widget when it is added, since it does not set it, they take the value of (1, 1), that is, the size of the window.
The solution is to set size_hint to (None, None), in addition to using allow_stretch in True and keep_ratio in False. In the code I have set the block pos_hint to (0.5, 0.5) and it will anchor it to that position so it will not move, if you want it to be able to move you must set the pos, not the pos_hint.
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
import random
import time
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
#############################################################################
class Collider(Image):
pass
#############################################################################
root = FloatLayout()
class GameScreen(Screen):
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.wimg = Basic(size = (32,32), pos=(200, 100), source='sprite.png', size_hint=(None, None), allow_stretch=True, keep_ratio=False)
self.block = Collider(size = (32,32), pos_hint={'x': 0.5, 'y':0.5}, source = 'block.png', size_hint=(None, None), allow_stretch=True, keep_ratio=False)
def playy(self):
root.add_widget(self.wimg)
Clock.schedule_interval(self.wimg.update, 1.0 / 60.0)
def worldgen1(self):
self.add_widget(root)
root.add_widget(self.block)
def on_enter(self):
self.worldgen1()
self.playy()
#############################################################################
class Basic(Image):
pFrame = 0
def __init__(self, **kwargs):
super(Basic, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.x -= 10
elif keycode[1] == 'right':
self.x += 10
elif keycode[1] == 'up':
self.y += 10
elif keycode[1] == 'down':
self.y -= 10
else:
return False
return True
def update(self, dt):
self.pFrame += 1
if self.parent.parent.block.collide_widget(self.parent.parent.wimg):
print ("collide with", self.parent.parent.block)
#############################################################################
class MeinApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(GameScreen(name='gameplay'))
return sm
if __name__ == '__main__':
MeinApp().run()

How do you add a controllable graphic with an image overtop in kivy?

I am new to python and have messed around with Kivy a little. This is the first app of my own design I've been tying to make. The goal is for it to be a game where there is a character that moves in all directions around the screen. My problem right now is that I can't get the character widget to display and I don't know if it's a problem with the widget or the image in the widget. When I run the program all I get is a black screen and no errors. Can anyone see where I went wrong?
Also if you have any recommendations in a better way to structure anything it would be appreciated :)
import kivy
kivy.require('1.7.2')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import NumericProperty
from kivy.graphics import Rectangle, Color, Canvas
from kivy.uix.image import Image
class WidgetDrawer(Widget):
def __inti__(self, imageStr, **kwargs):
super(WidgetDrawer,self).__inti__(**kwargs)
with self.canvas:
self.size = (Window.width*.05, Window.width*.05)
self.x = self.center_x
self.y = self.center_y
self.pos = (self.x, self.y)
self.rect_pl = Rectangle(source= imageStr, pos=self.pos, size=self.size)
self.bind(pos=self.update_graphics_pos)
self.rect_pl.pos = self.pos
def update_graphic_pos(self, value):
self.rect_pl.pos = value
def setSize(self, width, height):
self.size = (width,height)
class Player(WidgetDrawer):
impulse_x = 3
impulse_y = 3
winre = -0.1
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
def move(self):
self.x = self.x + self.velocity_x
self.y = self.y + self.velocity_y
if self.x > Window.width*.95 or self.x < Window.width*.05:
velocity_x = 0
if self.y > Window.height*.95 or self.y < Window.height*.05:
velocity_y = 0
def determineVelocity(self):
self.velocity_x = self.impulse_x + self.winre
self.velocity_y = self.impulse_y + self.winre
def update(self):
self.determineVelocity()
self.move()
class GUI(Widget):
def __init___(self, **kwargs):
super(GUI, self).__init__(**kwargs)
self.character = Player(imageStr = './character.png')
self.character.x = Window.width/4
self.character.y = Window.height/2
self.add_widget(self.character)
class GameApp(App):
def build(self):
parent = Widget()
app = GUI()
parent.add_widget(app)
return parent
if __name__ == '__main__':
GameApp().run()
The problem is self.add_widget(self.character) i.e. adding widget in __init__ method. Try to run python main.py -m inspector, Ctrl+E and get to GUI(). No children, nothing. Add children after __init__.
About the structure:
use kv language
use one naming style
fix typos(__inti__ != __init__)
if you have 1.7.2 version, you definitely need to update asap

Categories