I am developing a game in which users must match images by their initial letter (in Spanish), so that when they drag to a point (the cauldron) an image that begins with the correct letter (in this case the igloo, the Indian and the magnet) this image disappears.Example screen
In other words, basically, an image disappears when dragged to a specific point.
*.kv
#:import win kivy.core.window
<Picture@Scatter>:
source: None
on_size: self.center = win.Window.center
size: image.size
size_hint: None, None
do_scale: False
do_rotation: False
Image:
id: image
source: root.source
size: 250, 250 / self.image_ratio
<Relaciona3x2>:
AnchorLayout:
Image:
source: 'data/img/fondobosque.jpg'
allow_stretch: True
keep_ratio: False
FloatLayout:
size_hint: 1, 1
Image:
id: img003
source: 'data/img/caldero.png'
size_hint: 0.55, 0.55
pos_hint: {"center_x": 0.5, "center_y": 0.20}
Button:
size_hint:.06, 0.1
text: "Volver al menú"
on_release: app.root.current = 'menu'
Picture:
id: potionscatter
source: "data/img/letra_i/iglú.png"
pos: 175, 680
Picture:
source: "data/img/letra_i/indio.png"
pos: 835, 680
Picture:
source: "data/img/letra_m/moto.png"
pos: 1495, 680
Picture:
source: "data/img/letra_u/uña.png"
pos: 175, 420
Picture:
source: "data/img/letra_i/imán_1.png"
pos: 835, 420
Picture:
source: "data/img/letra_u/urraca.png"
pos: 1495, 420
<Relaciona4x2Screen>:
AnchorLayout:
Image:
source: 'data/img/fondobosque.jpg'
allow_stretch: True
keep_ratio: False
FloatLayout:
size_hint: 1, 1
Image:
id: img003
source: 'data/img/caldero.png'
size_hint: 0.55, 0.55
pos_hint: {"center_x": 0.5, "center_y": 0.20}
Button:
size_hint:.06, 0.1
text: "Volver al menú"
on_release: app.root.current = 'menu'
<Relaciona5x2Screen>:
AnchorLayout:
Image:
source: 'data/img/fondobosque.jpg'
allow_stretch: True
keep_ratio: False
FloatLayout:
size_hint: 1, 1
Image:
id: img003
source: 'data/img/caldero.png'
size_hint: 0.55, 0.55
pos_hint: {"center_x": 0.5, "center_y": 0.20}
Button:
size_hint:.06, 0.1
text: "Volver al menú"
on_release: app.root.current = 'menu'
relaciona.py
__all__ = ('Relaciona3x2', 'Relaciona4x2', 'Relaciona5x2')
import kivy
kivy.require('1.0.6')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file('relaciona.kv')
class Relaciona3x2(Screen):
pass
class Relaciona4x2(Screen):
pass
class Relaciona5x2(Screen):
pass
main.py
import kivy
kivy.require('1.0.6')
from kivy.uix.popup import Popup
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.animation import Animation
from kivy.uix.button import Button
from kivy.uix.scatter import Scatter
from kivy.logger import Logger
from kivy.uix.gesturesurface import GestureSurface
from letras import DrawGame, ImageEx, SoundEx, ContainerBox
from explota import BubblePop, BubbleGame
from relaciona import *
from borra import Borra
from caza import Caza
from config import Config
from kivy.core.window import Window
Builder.load_file('design.kv')
class MyScreenManager(ScreenManager):
def __init__(self):
super (MyScreenManager, self).__init__()
class HomeMenu(Screen):
pass
class LetrasScreen(Screen):
pass
class ExplotaScreen(Screen):
pass
class Relaciona3x2Screen(Screen):
pass
class Relaciona4x2Screen(Screen):
pass
class Relaciona5x2Screen(Screen):
pass
class BorraScreen(Screen):
pass
class CazaScreen(Screen):
pass
class ConfigScreen(Screen):
pass
class myApp(App):
def build(self):
Window.fullscreen = 'auto'
return MyScreenManager()
def on_pause(self):
return True
def on_resume(self):
pass
myApp().run()
I have used DragNDropWidget to solve this problem. It's quite simple to use but now I don't know how to change the size of the buttons, I would like them to be bigger and somewhat separated from each other.
DragNDropWidget.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from kivy.core.window import Window
from kivy.animation import Animation
import copy
from kivy.uix.widget import Widget
from kivy.properties import (
ListProperty, NumericProperty, BooleanProperty, ObjectProperty)
class DragNDropWidget(Widget):
# let kivy take care of kwargs and get signals for free by using
# properties
droppable_zone_objects = ListProperty([])
bound_zone_objects = ListProperty([])
drag_opacity = NumericProperty(1.0)
drop_func = ObjectProperty(None)
drop_args = ListProperty([])
remove_on_drag = BooleanProperty(True)
def __init__(self, **kw):
super(DragNDropWidget, self).__init__(**kw)
self.register_event_type("on_drag_start")
self.register_event_type("on_being_dragged")
self.register_event_type("on_drag_finish")
self.register_event_type("on_motion_over")
self.register_event_type("on_motion_out")
self._dragged = False
self._dragable = True
self._fired_already = False
def set_dragable(self, value):
self._dragable = value
def set_remove_on_drag(self, value):
"""
This function sets the property that determines whether the dragged widget is just copied from its parent or taken from its parent
@param value: either True or False. If True then the widget will disappear from its parent on drag, else the widget will jsut get copied for dragging
"""
self.remove_on_drag = value
def set_bound_axis_positions(self):
for obj in self.bound_zone_objects:
try:
if self.max_y < obj.y+obj.size[1]-self.size[1]:
self.max_y = obj.y+obj.size[1]-self.size[1]
except AttributeError:
self.max_y = obj.y+obj.size[1]-self.size[1]
try:
if self.max_x < obj.x+obj.size[0]-self.size[0]:
self.max_x = obj.x + obj.size[0]-self.size[0]
except AttributeError:
self.max_x = obj.x+obj.size[0]-self.size[0]
try:
if self.min_y > obj.y:
self.min_y = obj.y
except AttributeError:
self.min_y = obj.y
try:
if self.min_x > obj.x:
self.min_x = obj.x
except AttributeError:
self.min_x = obj.x
def on_touch_down(self, touch):
if self.collide_point(touch.x, touch.y) and self._dragable:
# detect if the touch is short - has time and end (if not dispatch drag)
if abs(touch.time_end - touch.time_start) > 0.2:
self.dispatch("on_drag_start")
def on_touch_up(self, touch):
if self._dragable and self._dragged:
self.short_touch = True
self.dispatch("on_drag_finish")
self.short_touch = False
def on_touch_move(self, touch):
if self._dragged and self._dragable:
x = touch.x
y = touch.y
try:
if touch.x < self.min_x:
x = self.min_x
if touch.x > self.max_x:
x = self.max_x
if touch.y < self.min_y:
y = self.min_y
if touch.y > self.max_y:
y = self.max_y
except AttributeError:
pass
self.pos = (x, y)
def easy_access_dnd(self, function_to_do, function_to_do_out, arguments = [], bind_functions = []):
"""
This function enables something that can be used instead of drag n drop
@param function_to_do: function that is to be called when mouse_over event is fired on the widget
@param bind_functions: what is really to be done - background function for GUI functionality
"""
Window.bind(mouse_pos=self.on_motion)
self.easy_access_dnd_function = function_to_do
self.easy_access_dnd_function_out = function_to_do_out
self.easy_access_dnd_function_aguments = arguments
self.easy_access_dnd_function_binds = bind_functions
def on_motion(self, etype, moutionevent):
if self.collide_point(Window.mouse_pos[0], Window.mouse_pos[1]):
if not self._fired_already:
self.dispatch("on_motion_over")
else:
self.dispatch("on_motion_out")
def on_motion_over(self):
self.easy_access_dnd_function(
self.easy_access_dnd_function_aguments,
self.easy_access_dnd_function_binds)
self._fired_already = True
def on_motion_out(self):
try:
self.easy_access_dnd_function_out()
except AttributeError:
pass
self._fired_already = False
def on_drag_start(self):
print ('drag start')
self.opacity = self.drag_opacity
self.set_bound_axis_positions()
self._old_drag_pos = self.pos
self._old_parent = self.parent
self._old_index = self.parent.children.index(self)
self._dragged = True
if self.remove_on_drag:
self.reparent(self)
else:
#create copy of object to drag
self.reparent(self)
# the final child class MUST implement __deepcopy__
# IF self.remove_on_drag == False !!! In this case this is
# met in DragableArhellModelImage class
copy_of_self = copy.deepcopy(self)
self._old_parent.add_widget(copy_of_self, index=self._old_index)
def on_drag_finish(self):
print ('drag finish')
if self._dragged and self._dragable:
self.opacity = 1.0
dropped_ok = False
for obj in self.droppable_zone_objects:
if obj.collide_point(*self.pos):
dropped_ok = True
if dropped_ok:
self.drop_func(*self.drop_args)
anim = Animation(opacity=0, duration=0.7, t="in_quad")
anim.bind(on_complete=self.deparent)
anim.start(self)
else:
anim = Animation(pos=self._old_drag_pos, duration=0.7, t="in_quad")
if self.remove_on_drag:
anim.bind(on_complete = self.reborn)
else:
anim.bind(on_complete = self.deparent)
anim.start(self)
self._dragged = False
def deparent(self, widget="dumb", anim="dumb2"):
self.get_root_window().remove_widget(self)
def on_being_dragged(self):
print ('being dragged')
def reborn(self, widget, anim):
self.deparent()
self._old_parent.add_widget(self, index=self._old_index)
def reparent(self, widget):
parent = widget.parent
orig_size = widget.size
if parent:
parent.remove_widget(widget)
parent.get_root_window().add_widget(widget)
widget.size_hint = (None, None)
widget.size = orig_size
DragableButton.py
Created on Oct 24, 2012
@author: Pavel Kostelnik
'''
from DragNDropWidget import DragNDropWidget
from kivy.uix.button import Button
class DragableButton(Button, DragNDropWidget):
'''
classdocs
'''
def __init__(self, **kw):
'''
Constructor
'''
#Button.__init__(self, **kw)
super(DragableButton, self).__init__(**kw)
self.size_hint = (None, None)
def __deepcopy__(self, dumb):
return DragableButton(text=self.text,
droppable_zone_objects=self.droppable_zone_objects,
bound_zone_objects=self.bound_zone_objects,
drag_opacity=self.drag_opacity,
drop_func=self.drop_func,
remove_on_drag=self.remove_on_drag)
arrastrar.py
__all__ = ('Relaciona3x2', 'Relaciona4x2', 'Relaciona5x2')
import kivy
kivy.require('1.0.6')
from DragableButton import DragableButton
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file('arrastrar.kv')
class Relaciona3x2(Screen):
pass
class Relaciona4x2(Screen):
pass
class Relaciona5x2(Screen):
pass
class ArrastraApp(App):
def build(self):
#Window.fullscreen = 'auto'
return Relaciona3x2()
def greet(self):
print('Draggin done!')
if __name__ == "__main__":
ArrastraApp().run()
arrastrar.kv
#:kivy 1.9.0
<Relaciona3x2>:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/fondobosque.jpg'
BoxLayout:
orientation: 'vertical'
BoxLayout:
id: from_box
DragableButton:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/letra_i/iglu.png'
bound_zone_objects: [from_box, to_box ]
droppable_zone_objects: [to_box, ]
drop_func: app.greet
DragableButton:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/letra_i/indio.png'
bound_zone_objects: [from_box, to_box, ]
droppable_zone_objects: [to_box, ]
drop_func: app.greet
DragableButton:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/letra_m/moto.png'
bound_zone_objects: [from_box, to_box, ]
#droppable_zone_objects: [to_box, ]
drop_func: app.greet
BoxLayout:
id: from_box
DragableButton:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/letra_u/una.png'
bound_zone_objects: [from_box, to_box, ]
#droppable_zone_objects: [to_box, ]
drop_func: app.greet
DragableButton:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/letra_i/iman_1.png'
bound_zone_objects: [from_box, to_box, ]
droppable_zone_objects: [to_box, ]
drop_func: app.greet
DragableButton:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: 'data/img/letra_u/urraca.png'
bound_zone_objects: [from_box, to_box, ]
#droppable_zone_objects: [to_box, ]
drop_func: app.greet
Image:
id: to_box
source: "data/img/caldero.png"
<Relaciona4x2>:
AnchorLayout:
Image:
source: "data/img/fondobosque.jpg"
allow_stretch: True
keep_ratio: False
<Relaciona5x2>:
AnchorLayout:
Image:
source: "data/img/fondobosque.jpg"
allow_stretch: True
keep_ratio: False