atlasを使って画像表示 / ドラッグで移動可能なウィジェット - Kivy Advent Calendar 2013

何となくカードゲームを作ってみたかったので、カードの画像が1枚に収まってる素材を探してきて、それをatlasで表示してみます。
カードはドラッグで移動させたいので、Scatterをあわせてみました。
ランダムにばらまいてみました。まだ全然ゲームにはなってません... いや神経衰弱はできるかな?


(/sdcard/kivy/cards/)

trump.gif カードの素材 (http://sozai.7gates.net/docs/trump/)
cards.atlas 素材の座標位置を示すファイル
main.py

(cards.atlas)

{
  "trump.gif":{
    "SA":[  0,540,60,90], "HA":[ 60,540,60,90], "DA":[120,540,60,90], "CA":[180,540,60,90],
    "S2":[  0,450,60,90], "H2":[ 60,450,60,90], "D2":[120,450,60,90], "C2":[180,450,60,90],
    "S3":[  0,360,60,90], "H3":[ 60,360,60,90], "D3":[120,360,60,90], "C3":[180,360,60,90],
    "S4":[  0,270,60,90], "H4":[ 60,270,60,90], "D4":[120,270,60,90], "C4":[180,270,60,90],
    "S5":[  0,180,60,90], "H5":[ 60,180,60,90], "D5":[120,180,60,90], "C5":[180,180,60,90],
    "S6":[  0, 90,60,90], "H6":[ 60, 90,60,90], "D6":[120, 90,60,90], "C6":[180, 90,60,90],
    "S7":[  0,  0,60,90], "H7":[ 60,  0,60,90], "D7":[120,  0,60,90], "C7":[180,  0,60,90],

    "S8":[240,540,60,90], "H8":[300,540,60,90], "D8":[360,540,60,90], "C8":[420,540,60,90],
    "S9":[240,450,60,90], "H9":[300,450,60,90], "D9":[360,450,60,90], "C9":[420,450,60,90],
    "ST":[240,360,60,90], "HT":[300,360,60,90], "DT":[360,360,60,90], "CT":[420,360,60,90],
    "SJ":[240,270,60,90], "HJ":[300,270,60,90], "DJ":[360,270,60,90], "CJ":[420,270,60,90],
    "SQ":[240,180,60,90], "HQ":[300,180,60,90], "DQ":[360,180,60,90], "CQ":[420,180,60,90],
    "SK":[240, 90,60,90], "HK":[300, 90,60,90], "DK":[360, 90,60,90], "CK":[420, 90,60,90],

    "J1":[240,  0,60,90], "J2":[300,  0,60,90], "N": [360,  0,60,90]
  }
}

(main.py)

from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.scatter import Scatter
from random import randint

from kivy.lang import Builder
Builder.load_string('''\
:
    canvas.before:
        Color:
            rgb: 0, 0.3, 0.1
        Rectangle:
            pos: self.pos
            size: self.size
:
    suit: 'N'
    rank: ''
    face: _face
    do_rotation: True
    do_scale: False
    auto_bring_to_front: True
    do_collide_after_children: True
    size: (120, 150)
    size_hint: (None, None)
    ToggleButton:
        id: _face
        size: (60, 90)
        size_hint: (None, None)
        background_normal: 'atlas://cards/N'
        background_down: 'atlas://cards/%s%s' % (self.parent.suit, self.parent.rank)
''')

class CardTable(RelativeLayout):
    pass

class Card(Scatter):

    def on_touch_up(self, touch):
        if self.collide_point(*touch.pos):
            self.face.state = 'down' if self.face.state == 'normal' else 'normal'

class CardTableApp(App):

    def build(self):
        self.table = CardTable()
        for suit in list('SHDC'):
             for rank in list('A23456789TJQK'):
                 card = Card()
                 card.suit = suit
                 card.rank = rank
                 card.pos = (randint(50, 1150), randint(50, 1870))
                 self.table.add_widget(card)
        return self.table

if __name__ == '__main__':
    CardTableApp().run()

追記

  • いろいろ調整してはいますが、さすがに小サイズのウィジェットに「カードへのタッチで開く/閉じるをトグルにする」と「ドラッグして動かす」の両方を持たせるのは無理がありました。本当にゲームを作るときは別のUIに出来ないか検討してみます...
  • 画面サイズを決めうちにしているところがあります。kivy.core.windowで取れるはずなので、後で修正すると思います...