Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Where is the bug?... in .update(self.dt)
-
Hello everyone.
I'm trying to adapt the card game shown below to the Pythonista 3, but I find a bug that I am unable to resolve. It appears in the "draw" function and the error is "init() missing 4 required positional arguments: r, g, b, a,...". Some clue?
Best regards
# Card Game # # In this game, you have to find matching pairs of cards. # This scene consists entirely of layers and demonstrates some # interesting animation techniques. from scene import * from random import shuffle from functools import partial import sound class Game(Scene): def setup(self): self.root_layer = Layer(self.bounds) for effect in ['Click_1', 'Click_2', 'Coin_2', 'Coin_5']: sound.load_effect(effect) self.deal() def draw(self): background(0.0, 0.2, 0.3) self.root_layer.update(self.dt) ### bug??? self.root_layer.draw() def deal(self): images = ['Rabbit_Face', 'Mouse_Face', 'Cat_Face', 'Dog_Face', 'Octopus', 'Bear_Face', 'Chicken', 'Cow_Face'] * 2 for image in images: load_image(image) shuffle(images) self.root_layer.sublayers = [] self.cards = [] self.selected = [] card_size = 96 if self.size.w > 700 else 64 width = (card_size + 5) * 4 offset = Point((self.size.w - width)/2, (self.size.h - width)/2) for i in range(len(images)): x, y = i % 4, i // 4 card = Layer(Rect(offset.x + x * (card_size + 5), offset.y + y * (card_size + 5), card_size, card_size)) card.card_image = images[i] card.background = Color(0.9, 0.9, 0.9, 1) card.stroke = Color(1, 1, 1, 1) card.stroke_weight = 4.0 self.add_layer(card) self.cards.append(card) self.touch_disabled = False def touch_began(self, touch): if self.touch_disabled or len(self.cards) == 0: return if len(self.selected) == 2: self.discard_selection() return for card in self.cards: if card in self.selected or len(self.selected) > 1: continue if touch.location in card.frame: def reveal_card(): card.image = card.card_image card.animate('scale_x', 1.0, 0.15, completion=self.check_selection) self.selected.append(card) self.touch_disabled = True card.animate('scale_x', 0.0, 0.15, completion=reveal_card) card.scale_y = 1.0 card.animate('scale_y', 0.9, 0.15, autoreverse=True) sound.play_effect('Click_1') break def discard_selection(self): sound.play_effect('Click_2') for card in self.selected: def conceal(card): card.image = None card.animate('scale_x', 1.0, 0.15) card.animate('scale_x', 0.0, 0.15, completion=partial(conceal, card)) card.scale_y = 1.0 card.animate('scale_y', 0.9, 0.15, autoreverse=True) self.selected = [] def check_selection(self): self.touch_disabled = False if len(self.selected) == 2: card_img1 = self.selected[0].card_image card_img2 = self.selected[1].card_image if card_img1 == card_img2: sound.play_effect('Coin_5') for c in self.selected: c.animate('background', Color(0.5, 1, 0.5, 1)) self.cards.remove(c) self.selected = [] if len(self.cards) == 0: self.win() def new_game(self): sound.play_effect('Coin_2') self.deal() self.root_layer.animate('scale_x', 1.0) self.root_layer.animate('scale_y', 1.0) def win(self): self.delay(0.5, partial(sound.play_effect, 'Powerup_2')) font_size = 100 if self.size.w > 700 else 50 text_layer = TextLayer('Well Done!', 'Futura', font_size) text_layer.frame.center(self.bounds.center()) overlay = Layer(self.bounds) overlay.background = Color(0, 0, 0, 0) overlay.add_layer(text_layer) self.add_layer(overlay) overlay.animate('background', Color(0.0, 0.2, 0.3, 0.7)) text_layer.animate('scale_x', 1.3, 0.3, autoreverse=True) text_layer.animate('scale_y', 1.3, 0.3, autoreverse=True) self.touch_disabled = True self.root_layer.animate('scale_x', 0.0, delay=2.0, curve=curve_ease_back_in) self.root_layer.animate('scale_y', 0.0, delay=2.0, curve=curve_ease_back_in, completion=self.new_game) run(Game())
-
Older scene programs were based on the Classic Rendering Loop.
-
There is a point too much in your code.
self.root_layer.update(self.dt)_ ### bug???
-
After you match two tiles, the script will fail in the way that @david suggests.
-
I did run your your code now. The reason why the script raises the exception is a namespace conflict in pythonistas
scene
namespace. If you follow the trace you will see that the exception is raised at scene_drawing.py line 253:... ... isinstance(self.to_value, Color): 253 value = Color() ...
The
Color
type does not support a parameterless constructor anymore. There is nothing you can do because the file scene_drawing is read only (you could circumvent that but that does not seem to be a good idea). You would have to changevalue = Color()
to something likevalue = Color(1, 1, 1, 1)
. -
This seems to be a bug in recordtype... or should I say an incompatibility with Python 3.
In py3:
cls.__init__.im_func.func_defaults = init_defaults should be cls.__init__.__defaults__= init_defaults
-
Hi all... Yes, the "problem" appears in the line "253 value = Color()" in scene_drawing.py
Following the line that says @ccc, I understand that I have to change the "classic rendering loop" by "Node/Action" ... any suggestions?
-
you could also just monkey patch Color:
_scene_types.Color.__init__.__defaults__=(0,0,0,0)
-
Based on @JonB suggestion above, these lines fixed things...
try: # Python 3 Color.__init__.__defaults__ = (0, 0, 0, 0) except AttributeError: pass # Python 2
-
Nice. This work. Thank you!