This is a life counter that I am using together with my friends for card games (Magic the Gathering).
For those who know the game, it is actually designed for 1vs1 Commander. It provides you with the possibility to take notes about life points, commander damage, and also to roll a dice to decide who has to start the game.
I would like to know if it is well written (in a "Pythonic" way) or if there is something that I can learn from the community to improve my sintax and my coding style: in fact, I am new to Python and to coding (to give you an idea of my level, I have started writing this app 1 month ago, and actually I code 2-3 hours a week).
Please note that the functions set_20
, set_30
, set_40
are not actually called from the interface: in a future version there will be a "settings" section (that is why there is also a Settings
screen at the end of the builder) but I am still working on it.
Despite what is written in the above paragraph, the app works correctly: I am writing it following the Agile methodology, so I am adding pieces of functions/code when I have an idea without compromising the functionality of the app.
If you wish, you could also follow the project on Github: the code below is in the v2
branch, the master
contains the first version of the app.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
import random
Builder.load_string('''
<LifeCounter>:
ScreenManager:
size_hint: 20, 1
id: _screen_manager
Screen:
name: 'MainScreen'
BoxLayout:
orientation: 'vertical'
padding: 50
FloatLayout:
orientation: 'horizontal'
Button:
text: "Me"
font_size: '20sp'
pos_hint: {'x':.0, 'y':.3}
size_hint: .4, .6
on_release: root.change_name(self)
Button:
text: "Opponent"
font_size: '20sp'
pos_hint: {'x':.55, 'y':.3}
size_hint: .4, .6
on_release: root.change_name(self)
FloatLayout:
orientation: 'horizontal'
Label:
id: l_label
font_size: '40sp'
pos_hint: {'x':.0, 'y':.3}
size_hint: .4, .8
text: str(root.count)
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Label:
id: l_label2
font_size: '40sp'
pos_hint: {'x':.55, 'y':.3}
size_hint: .4, .8
text: str(root.count2)
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
orientation: 'horizontal'
Button:
text: "-"
font_size: '30sp'
pos_hint: {'x':.0, 'y':.3}
size_hint: .2, .8
on_release: root.decr()
Button:
text: "+"
font_size: '30sp'
pos_hint: {'x':.20, 'y':.3}
size_hint: .2, .8
on_release: root.incr()
Button:
text: "-"
font_size: '30sp'
pos_hint: {'x':.55, 'y':.3}
size_hint: .2, .8
on_release: root.decr2()
Button:
text: "+"
font_size: '30sp'
pos_hint: {'x':.75, 'y':.3}
size_hint: .2, .8
on_release: root.incr2()
FloatLayout:
orientation: 'horizontal'
Button:
text: "Commander A"
font_size: '20sp'
pos_hint: {'x':.0, 'y':.3}
size_hint: .4, .8
on_release: root.change_name(self)
Button:
text: "Commander B"
font_size: '20sp'
pos_hint: {'x':.55, 'y':.3}
size_hint: .4, .8
on_release: root.change_name(self)
FloatLayout:
orientation: 'horizontal'
Label:
id: l_label
font_size: '40sp'
pos_hint: {'x':.0, 'y':.3}
size_hint: .4, .8
text: str(root.cmdcount)
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Label:
id: l_label2
font_size: '40sp'
pos_hint: {'x':.55, 'y':.3}
size_hint: .4, .8
text: str(root.cmdcount2)
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
orientation: 'horizontal'
Button:
text: "-"
font_size: '30sp'
pos_hint: {'x':.0, 'y':.3}
size_hint: .2, .8
on_release: root.decrcmd()
Button:
text: "+"
font_size: '30sp'
pos_hint: {'x':.20, 'y':.3}
size_hint: .2, .8
on_release: root.incrcmd()
Button:
text: "-"
font_size: '30sp'
pos_hint: {'x':.55, 'y':.3}
size_hint: .2, .8
on_release: root.decrcmd2()
Button:
text: "+"
font_size: '30sp'
pos_hint: {'x':.75, 'y':.3}
size_hint: .2, .8
on_release: root.incrcmd2()
FloatLayout:
orientation: 'horizontal'
Button:
text: "Roll a dice"
pos_hint: {'x':.0, 'y':.005}
size_hint: .4, .8
font_size: '20sp'
on_release: root.roll_dice()
Label:
text: str(root.dice)
pos_hint: {'x':.55, 'y':.005}
size_hint: .4, .8
font_size: '20sp'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
orientation: 'horizontal'
Button:
text: "-->"
pos_hint: {'x':.65, 'y': .0}
size_hint: .3, .8
on_release: pass
Screen:
name: 'Settings'
BoxLayout:
orientation: 'vertical'
padding: 50
FloatLayout:
orientation: 'horizontal'
Button:
text: "20"
pos_hint: {'x':.12, 'y':.6}
size_hint: .2, .5
font_size: '20sp'
on_release: root.set_20()
Button:
text: "30"
pos_hint: {'x':.40, 'y':.6}
size_hint: .2, .5
font_size: '20sp'
on_release: root.set_30()
Button:
text: "40"
pos_hint: {'x':.68, 'y':.6}
size_hint: .2, .5
font_size: '20sp'
on_release: root.set_40()
''')
class LifeCounter(BoxLayout):
count = NumericProperty(30)
count2 = NumericProperty(30)
cmdcount = NumericProperty(0)
cmdcount2 = NumericProperty(0)
dice = NumericProperty(0)
def __init__(self, **kwargs):
super(LifeCounter, self).__init__(**kwargs)
self.hide_input = TextInput(size_hint=(None, None),
size=(0, 0),
multiline=False)
self.hide_input_bind = None
# The functions below update the names of the players and of the commanders.
def change_name(self, instance):
if self.hide_input_bind:
self.hide_input.unbind_uid('text',
self.hide_input_bind)
self.hide_input.text = instance.text
self.hide_input.focus = True
self.hide_input_bind = self.hide_input.fbind('text',
self._update_text,
instance)
def _update_text(self, button,
instance, value):
button.text = value
# The functions below update the labels of the player's life points.
def incr(self):
self.count += 1
def decr(self):
self.count -= 1
def incr2(self):
self.count2 += 1
def decr2(self):
self.count2 -= 1
# The functions below update the labels of the commander damage.
def incrcmd(self):
self.cmdcount += 1
def decrcmd(self):
self.cmdcount -= 1
def incrcmd2(self):
self.cmdcount2 += 1
def decrcmd2(self):
self.cmdcount2 -= 1
# The functions below set the lifepoints to 20, 30, 40 according to user's needs.
def set_20(self):
self.count = 20
self.count2 = 20
def set_30(self):
self.count = 30
self.count2 = 30
def set_40(self):
self.count = 40
self.count2 = 40
# The function below rolls the dice
def roll_dice(self):
self.min = 1
self.max = 20
self.dice = random.randint(self.min,
self.max)
class MtgLifeCounter(App):
def build(self):
return LifeCounter()
if __name__ == '__main__':
MtgLifeCounter().run()