Forum Archive

scenes updating each other’s variables

resserone13

Is there a way I can have one scene update a variable on another scene? How would I adjust a variable on a Modal scene that then updates a variable on the main scene? When a player runs runs out of money I have a modal scene pop up asking if the player would like a loan. They adjust the loan amount and press “ take loan” once they press take loan the modal scene is dismissed and I would like the bankroll amount on the main scene to be updated from the loan amount on the modal scene.

JonB

Rather than calling your scene like

run(MyScene())

Assign it to a variable.

main_scene=MyScene()
run(main_scene)

Then your modal scene can access the global main_scene.

Or, if you launch your scene inside a function, you would create an attribute in your modal scene that points to the main scene.

modal_scene=MyModalScene()
modal_scene.main_scene = main_scene

Then the modal scene can access this.main_scene.

resserone13

@JonB how would I do it in this example?


from scene import *
import sound
import random
import math
A = Action  

class MyScene (Scene):
    def setup(self):

        self.bankroll_amount = 0

        self.text = LabelNode(
            'MAIN SCREEN',
            ('Apple Color Emoji', 40), 
            position= self.size/2,
            parent=self
            )

        self.next_screen = LabelNode(
            'Next SCREEN',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.55, self.size.h/2 * 1.33),
            parent=self
            )   

        self.bankroll_amount_label = LabelNode(
            f'{self.bankroll_amount:,}', 
            font = ('Bodoni 72', 28), 
            position = (self.size.w/2 * 1.79, self.size.h/2 * 1.66), 
            color = 'gold', 
            parent=self
            )       

    def update(self):
        pass

    def touch_began(self, touch):
        if touch.location in self.next_screen.frame:
            self.present_modal_scene(Screen_1())

    def touch_ended(self, touch):
        pass

class Screen_1(Scene):
    def setup(self):

        self.bg_color = SpriteNode('plc:Grass_Block', position= (self.size/2), scale=25, parent=self)

        self.text_1 = LabelNode(
            '1st SCREEN',
            ('Apple Color Emoji', 40), 
            position = (self.size.w/2 * 0.55, self.size.h/2 * 0.99),
            parent=self)

        self.next_screen_1 = LabelNode(
            '1st button',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.40, self.size.h/2 * 1.33),
            parent=self
            )           

        self.loan_amount = 0

        self.loan_label = LabelNode(
            'Loan Amount',
            ('DIN Condensed', 40),
            color= 'black',
            position = (self.size.w/2, self.size.h/2 * 1.10)
            )

        self.loan_amount_label = LabelNode(
            f'${self.loan_amount}',
            ('Bodoni 72', 35),
            color= 'black',         
            position = (self.size.w/2, self.size.h/2 * 0.85)
            )           

        self.take_loan = LabelNode(
            'Take Loan',
            ('Avenir Next Condensed', 30),
            position = (self.size.w/2, self.size.h/2 * 0.55),
            color= 'black'          
            )

        self.inc_loan_btn = SpriteNode(
            'emj:Red_Triangle_1',
            position= (self.size.w/2 * 1.33, self.size.h/2 * 1.25),
            scale=2
            )

        self.dec_loan_btn = SpriteNode(
            'emj:Red_Triangle_2',
            position= (self.size.w/2 * 1.33, self.size.h/2 * 0.75),
            scale=2
            )           

        self.add_child(self.loan_label)
        self.add_child(self.loan_amount_label)
        self.add_child(self.take_loan)
        self.add_child(self.inc_loan_btn)
        self.add_child(self.dec_loan_btn)   

    def touch_began(self, touch):
        if touch.location in self.next_screen_1.frame:
            self.present_modal_scene(Screen_2())

        if touch.location in self.take_loan.frame:
            self.bankroll_amount = self.loan_amount
            self.dismiss_modal_scene()          

        #--- inc loan ---
        if touch.location in self.inc_loan_btn.frame:
            self.loan_amount += 500
            self.loan_amount_label.text = f'${self.loan_amount}'
            if self.loan_amount >= 10_000:
                self.loan_amount = 10_000
                self.loan_amount_label.text = f'${self.loan_amount}'

        #--- dec loan ---                               
        if touch.location in self.dec_loan_btn.frame:
            self.loan_amount -= 500
            self.loan_amount_label.text = f'{self.loan_amount}'
            if self.loan_amount < 0:
                self.loan_amount = 0
                self.loan_amount_label.text = f'{self.loan_amount}'         

    def touch_ended(self, touch):
        pass


class Screen_2(Scene):

    def setup(self):

        self.bg_color = SpriteNode('plc:Brown_Block', position= (self.size/2), scale=25, parent=self)               
        self.text_2 = LabelNode(
            '2nd SCREEN',
            ('Apple Color Emoji', 40), 
            position= self.size/2,
            parent=self)

        self.next_screen_2 = LabelNode(
            '2nd button',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.2, self.size.h/2),
            parent=self)            

    def touch_began(self, touch):

        if touch.location in self.next_screen_2.frame:
            self.dismiss_modal_scene()


    def touch_ended(self, touch):
        pass


if __name__ == '__main__':
    run(MyScene(), LANDSCAPE, show_fps=False)


JonB
# instead of
if __name__ == '__main__':
    run(MyScene(), LANDSCAPE, show_fps=False)

# do 
main_scene=MyScene()
run(main_scene, LANDSCAPE, show_fps=False)

Then, your other scenes can access attributes of main_scene.

As an alternative, you use present_modal_scene. Use a variable for those modal scenes, then you can access attributes of the pop-up scenes after present_modal_scene completes.

resserone13

@JonB ive updated the run function to run off a variable. Is that literally all that’s needed. I ran the code with the change in the variable was not updated. I believe that your alternative method is what I’m already attempting to do in the example. I am very very new at not only Scene module and Pythonista but coding altogether. What else is needed besides putting in the class in a variable? How exactly do I access the attributes? Is my example Close to what your alternative method is? Thank you for taking the time to help me.

cvp

@resserone13 what @JonB advices is

def touch_began(self, touch):
        if touch.location in self.next_screen.frame:
            self.present_modal_scene(Screen_1())
            |            
            |            
            |            
            V           
def touch_began(self, touch):
        if touch.location in self.next_screen.frame:
            sc1 = Screen_1()    
            sc1.main_scene = self
            self.present_modal_scene(sc1)
cvp

@resserone13 then you can access bankroll_amount of the main scene in other scene by

self.main_scene.bankroll_amount
resserone13

@cvp @JonB I have incorporated your guises recommendations into my practice code and I’m getting an error I’ve never seen and can’t figure out. I’ve listed the error and the updated code below.

Error...

TypeError: bad argument type for built-in operation

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/var/containers/Bundle/Application/F3A42D55-5CB1-4DC2-AFF5-5BE7BB053375/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/scene.py", line 216, in _touch_began
self.presented_scene._touch_began(x, y, touch_id)
File "/var/containers/Bundle/Application/F3A42D55-5CB1-4DC2-AFF5-5BE7BB053375/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/scene.py", line 226, in _touch_began
self.touch_began(touch)
File "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/modal_practice.py", line 111, in touch_began
self.main.bankroll_amount_label.text = f'{self.main.bankroll_amount:,}',
File "/var/containers/Bundle/Application/F3A42D55-5CB1-4DC2-AFF5-5BE7BB053375/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/scene.py", line 280, in setattr
self.update_texture()
File "/var/containers/Bundle/Application/F3A42D55-5CB1-4DC2-AFF5-5BE7BB053375/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/scene.py", line 285, in update_texture
w, h = ui.measure_string(self.text, font=self.font)
SystemError: returned a result with an error set


from scene import *
import sound
import random
import math
A = Action  

class MyScene (Scene):
    def setup(self):

        self.bankroll_amount = 0

        self.text = LabelNode(
            'MAIN SCREEN',
            ('Apple Color Emoji', 40), 
            position= self.size/2,
            parent=self
            )

        self.next_screen = LabelNode(
            'Next SCREEN',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.55, self.size.h/2 * 1.33),
            parent=self
            )   

        self.bankroll_amount_label = LabelNode(
            f'{self.bankroll_amount:,}', 
            font = ('Bodoni 72', 28), 
            position = (self.size.w/2 * 1.79, self.size.h/2 * 1.66), 
            color = 'gold', 
            parent=self
            )       

    def update(self):
        pass

    def touch_began(self, touch):
        if touch.location in self.next_screen.frame:
            sc1 = Screen_1()
            sc1.main = self
            self.present_modal_scene(sc1)

    def touch_ended(self, touch):
        pass

class Screen_1(Scene):
    def setup(self):

        self.bg_color = SpriteNode('plc:Grass_Block', position= (self.size/2), scale=25, parent=self)

        self.text_1 = LabelNode(
            '1st SCREEN',
            ('Apple Color Emoji', 40), 
            position = (self.size.w/2 * 0.55, self.size.h/2 * 0.99),
            parent=self)

        self.next_screen_1 = LabelNode(
            '1st button',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.40, self.size.h/2 * 1.33),
            parent=self
            )           

        self.loan_amount = 0

        self.loan_label = LabelNode(
            'Loan Amount',
            ('DIN Condensed', 40),
            color= 'black',
            position = (self.size.w/2, self.size.h/2 * 1.10)
            )

        self.loan_amount_label = LabelNode(
            f'${self.loan_amount}',
            ('Bodoni 72', 35),
            color= 'black',         
            position = (self.size.w/2, self.size.h/2 * 0.85)
            )           

        self.take_loan = LabelNode(
            'Take Loan',
            ('Avenir Next Condensed', 30),
            position = (self.size.w/2, self.size.h/2 * 0.55),
            color= 'black'          
            )

        self.inc_loan_btn = SpriteNode(
            'emj:Red_Triangle_1',
            position= (self.size.w/2 * 1.33, self.size.h/2 * 1.25),
            scale=2
            )

        self.dec_loan_btn = SpriteNode(
            'emj:Red_Triangle_2',
            position= (self.size.w/2 * 1.33, self.size.h/2 * 0.75),
            scale=2
            )           

        self.add_child(self.loan_label)
        self.add_child(self.loan_amount_label)
        self.add_child(self.take_loan)
        self.add_child(self.inc_loan_btn)
        self.add_child(self.dec_loan_btn)   

    def touch_began(self, touch):
        if touch.location in self.next_screen_1.frame:
            self.present_modal_scene(Screen_2())

        if touch.location in self.take_loan.frame:
            self.main.bankroll_amount = self.loan_amount
            self.main.bankroll_amount_label.text = f'{self.main.bankroll_amount:,}', 
            self.dismiss_modal_scene()          

        #--- inc loan ---
        if touch.location in self.inc_loan_btn.frame:
            self.loan_amount += 500
            self.loan_amount_label.text = f'${self.loan_amount}'
            if self.loan_amount >= 10_000:
                self.loan_amount = 10_000
                self.loan_amount_label.text = f'${self.loan_amount}'

        #--- dec loan ---                               
        if touch.location in self.dec_loan_btn.frame:
            self.loan_amount -= 500
            self.loan_amount_label.text = f'${self.loan_amount}'
            if self.loan_amount < 0:
                self.loan_amount = 0
                self.loan_amount_label.text = f'${self.loan_amount}'            

    def touch_ended(self, touch):
        pass


class Screen_2(Scene):

    def setup(self):

        self.bg_color = SpriteNode('plc:Brown_Block', position= (self.size/2), scale=25, parent=self)               
        self.text_2 = LabelNode(
            '2nd SCREEN',
            ('Apple Color Emoji', 40), 
            position= self.size/2,
            parent=self)

        self.next_screen_2 = LabelNode(
            '2nd button',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.2, self.size.h/2),
            parent=self)            

    def touch_began(self, touch):

        if touch.location in self.next_screen_2.frame:
            self.dismiss_modal_scene()


    def touch_ended(self, touch):
        pass

main = MyScene()    

if __name__ == '__main__':
    run(main, LANDSCAPE, show_fps=False)

resserone13

I also tried just having everything inside of one scene and basically changing scenes by adding and removing nodes. It gives me the same error for some reason.


class MyScene (Scene):
    def setup(self):

        self.bankroll_amount = 0

        self.text = LabelNode(
            'MAIN SCREEN',
            ('Apple Color Emoji', 40), 
            position= self.size/2,
            parent=self
            )

        self.next_screen = LabelNode(
            'Next SCREEN',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.55, self.size.h/2 * 1.33),
            parent=self
            )   

        self.bankroll_amount_label = LabelNode(
            f'{self.bankroll_amount:,}', 
            font = ('Bodoni 72', 28), 
            position = (self.size.w/2 * 1.79, self.size.h/2 * 1.66), 
            color = 'gold', 
            parent=self
            )       

        self.bg_color_1 = SpriteNode(
            'plc:Grass_Block', 
            position= (self.size/2), 
            scale=25,
            )

        self.text_1 = LabelNode(
            '1st SCREEN',
            ('Apple Color Emoji', 40), 
            position = (self.size.w/2 * 0.55, self.size.h/2 * 0.99)
            )

        self.next_screen_1 = LabelNode(
            '1st button',
            ('Apple Color Emoji', 20), 
            position= (self.size.w/2 * 0.40, self.size.h/2 * 1.33)
            )           

        self.loan_amount = 0

        self.loan_label = LabelNode(
            'Loan Amount',
            ('DIN Condensed', 40),
            color= 'black',
            position = (self.size.w/2, self.size.h/2 * 1.10)
            )

        self.loan_amount_label = LabelNode(
            f'${self.loan_amount}',
            ('Bodoni 72', 35),
            color= 'black',         
            position = (self.size.w/2, self.size.h/2 * 0.85)
            )           

        self.take_loan = LabelNode(
            'Take Loan',
            ('Avenir Next Condensed', 30),
            position = (self.size.w/2, self.size.h/2 * 0.55),
            color= 'black'          
            )

        self.inc_loan_btn = SpriteNode(
            'emj:Red_Triangle_1',
            position= (self.size.w/2 * 1.33, self.size.h/2 * 1.25),
            scale=2
            )

        self.dec_loan_btn = SpriteNode(
            'emj:Red_Triangle_2',
            position= (self.size.w/2 * 1.33, self.size.h/2 * 0.75),
            scale=2
            )           

    def update(self):
        pass

    def touch_began(self, touch):
        if touch.location in self.next_screen.frame:

            self.text.remove_from_parent()
            self.next_screen.remove_from_parent()
            self.bankroll_amount_label.remove_from_parent()


            self.add_child(self.loan_label)
            self.add_child(self.loan_amount_label)
            self.add_child(self.take_loan)
            self.add_child(self.inc_loan_btn)
            self.add_child(self.dec_loan_btn)   

        if touch.location in self.next_screen_1.frame:
            pass

        if touch.location in self.take_loan.frame:
            self.add_child(self.text)
            self.add_child(self.next_screen)
            self.add_child(self.bankroll_amount_label)
            self.bankroll_amount = self.loan_amount
            self.bankroll_amount_label.text = f'{self.bankroll_amount:,}', 


        #--- inc loan ---
        if touch.location in self.inc_loan_btn.frame:
            self.loan_amount += 500
            self.loan_amount_label.text = f'${self.loan_amount}'
            if self.loan_amount >= 10_000:
                self.loan_amount = 10_000
                self.loan_amount_label.text = f'${self.loan_amount}'

        #--- dec loan ---                               
        if touch.location in self.dec_loan_btn.frame:
            self.loan_amount -= 500
            self.loan_amount_label.text = f'${self.loan_amount}'
            if self.loan_amount < 0:
                self.loan_amount = 0
                self.loan_amount_label.text = f'${self.loan_amount}'    

    def touch_ended(self, touch):
        pass



if __name__ == '__main__':
    run(MyScene(), LANDSCAPE, show_fps=False)

cvp

@resserone13 remove the comma at end of line

            self.main.bankroll_amount_label.text = f'{self.main.bankroll_amount:,}', 
resserone13

I was able to figure out why I was getting the error. There was an extra comma on the end of this line. I have it working both ways now with individual scenes and with everything in one scene and you just remove notes on and off to make the scenes.


            self.bankroll_amount_label.text = f'{self.bankroll_amount:,}'

cvp

We cross our posts 😂

resserone13

@cvp thank you. I just figured it out. Such a little thing.

resserone13

@cvp hahah. We did. At first I was having trouble with the multiple scenes but now I see a bit more of how I can work it both ways. I’m writing a card game to learn more coding. I’m gonna post it soon on GitHub. Hopefully in the next few days. I would sure like to hear what everyone thinks. I’m sure it will be interesting interesting. I wrote it with very few functions. Once I post it I would like to work on converting the code to more of an oop approach.

resserone13

Thanks so much. I’ve got it working and it feels awesome.

resserone13

@cvp said:

@resserone13 what @JonB advices is
def touch_began(self, touch): if touch.location in self.next_screen.frame: self.present_modal_scene(Screen_1()) | | | V def touch_began(self, touch): if touch.location in self.next_screen.frame: sc1 = Screen_1() sc1.main_scene = self self.present_modal_scene(sc1)

How would this work if a modal scene is presenting another modal scene on top of the main. I would like the 3rd scene (which is the 2nd modal scene on top of the main seven) to update a variable on the main scene. I’m sorry to ask but I’ve been rearranging the scenes and variables all day. I’ve also tried to do this when I first asked the question a while ago and can’t forgive it out.

cvp

@resserone13 said:

How would this work if a modal scene is presenting another modal scene on top of the main

I never use scene thus I'll let real specialists answer...

resserone13

@cvp ok. Thanks for the reply. @JonB do you mind helping out?

cvp

@resserone13 you could try, without promising it will work

try:
    # if current scene modal of main
    self.main_scene.bankroll_amount = ...
except:
    # if current scene modal of modal of main
    self.main_scene.main_scene.bankroll_amount = ...
resserone13

@cvp I’ll see if I can work this out. Thanks. I was think of some thing like.

If self.presented_scene() then. Such and such will happen but I haven’t try that too much. Main been re arranging the scenes and variables. I’ll let you know.

resserone13

@cvp I’ve got it to work by passing the variables from screen to screen. I have the 3rd screen update the 2nd screen and then the 2nd screen updates the 1st screen.

cvp

@resserone13 yes, sorry, I was just busy to try but what I had proposed is not good, forget it

cvp

@resserone13 perhaps a global could be sufficient

resserone13

@cvp I think I had trouble with globals once it gets into if statements and using them inside functions. I’ve noticed if you have self before everything you can use it anywhere in the class. I still have trouble with little things. I still have trouble making functions that I can use in multiple classes. I have to rewrite the function and all the scenes.

cvp

@resserone13 There are often several solutions to a problem even if one could be the best in a Python way, but if you are more comfortable with another one, why not, we are in free countries...
Anyway, you could post your code and perhaps @ccc or @mikael (and I'm sure, a lot of other guys) could have a look and give some professional advices, what I can't do, my Python code is rarely nice.

resserone13

@cvp Yeah you’re right. It doesn’t matter how I get it done as long as it gets done. There’s no rules. There’s just guidelines.

JonB

@resserone13 globals are easier to work with in scene, as long as you are careful with your naming so nothing else uses the same name, and can create the scenes before hand. if you are creating scenes in response to buttons, maybe not.

otherwise, the cleaner approach is to use attributes.

That is, within a method in your main_scene, you can do something like

self.modal_scene1 = reference_to_your_modalscene
self.modal_scene1.main_scene = self

but then of course, within your modal scene, you have to refer back to your main scene through the global, or through an attribute as shiwn above, so, if you are in a modal scene method:

self.main_scene

If you need to have multiple modal scenes that refer to each other, they can all interact back through main_scene, e.g.

self.main_scene.modal_scene1

As cvp said, if you want more specific help, post your code, and/or whatever traceback you are getting.

JonB

Just one other comment -- a function is something which is defined in the top level context. it does not refer to a specific class. genally it would not take a self argument.

A method is a def that is within a class. you said you were having trouble with functions that work with many classes. Maybe you meant methods that work with inheritance?

resserone13

@JonB here’s the whole game I’m marking. I have basically most of the things working. The settings allows you to adjust the time and the main issue I have now is when the new game starts it updates the time to the initial time not the time that was chosen in the settings page.


from scene import *
import sound
import random
import math

# --- To Do --- 
#animate time so that tim added floats away and dissappears

#add bomb emoji thatbsubtracts time. 

# --- Game variations ---
#make 3 5 and 10 second versions of the game. 

#Different colored circles pop up on the screen randomly and the play has to tap as many as they can within a minute

#As game proceeds more and more bubles ate added to the screen untill its full. when the screen is full game is over

A = Action

#slow flash screen 
'''self.run_action(
    A.repeat(
        A.sequence(
            A.call(self.move_bubble),
            A.fade_to(0, 1.5), A.fade_to(1, 1)), 0))'''

class  Intro(Scene):
    def setup(self):

        self.intro_bg = SpriteNode(position=self.size/2, color='black', size=self.size, alpha=1, parent=self)   

        '''self.intro_bubble = SpriteNode('emj:White_Circle', position=(self.size.w/2, self.size.h *0.25), parent=self)'''  

        self.tap = LabelNode('TappyTap', font=('MarkerFelt-Wide', 50), position=(self.size/2), parent=self)

        '''self.intro_bubble.run_action(
            A.repeat(
                A.sequence(
                    A.fade_to(0, 2), A.fade_to(1, 2)), 0))'''

        self.run_action(A.sequence(A.wait(10), A.call(self.dismiss_scene)))

    def dismiss_scene(self):
        self.dismiss_modal_scene()  

class Rules(Scene):
    def setup(self):

        self.rules_message = 'Rules: \nTap the white bubble \nas many times as you can \nbefore time runs out. \nTry to avoid the bombs \nor you will run out of time \nfaster than you think!'

        self.tip_message = 'Tip: \nLandscape will helps \ndivide the screen in half \nand you can use \nboth thumbs!'

        self.rules_node = Node(parent=self)
        self.rules_node.alpha=1

        self.rules_box = ShapeNode(ui.Path.rounded_rect(0, 0, self.size.w * 0.8, self.size.h *0.30, 20))
        self.rules_box.position=self.size.w/2, self.size.h * 0.70
        self.rules_box.fill_color='black'
        self.rules_box.line_width=4
        self.rules_box.stroke_color='white'
        self.add_child(self.rules_box)

        self.small_box = ShapeNode(ui.Path.rounded_rect(0, 0, self.size.w * 0.8, self.size.h *0.30, 20))
        self.small_box.position=(self.size.w/2, self.size.h * 0.55)
        self.small_box.fill_color='black'
        self.small_box.line_width=4
        self.small_box.stroke_color='white'
        self.small_box.anchor_point= 0.5, 1
        self.add_child(self.small_box)

        self.back = SpriteNode(
            'iow:ios7_redo_outline_32', position=(self.size.w * 0.10, self.size.h * 0.95), parent=self)

        self.rules_bg = SpriteNode(position=self.size/2, color='black', size=self.size, alpha=1, parent=self.rules_node)    

        self.rules_text = LabelNode(f'{self.rules_message}', font=('American Typewriter', 20), position=(self.size.w/2, self.size.h * 0.72),parent=self)

        self.tip_text = LabelNode(f'{self.tip_message}', font=('American Typewriter', 20), position=(self.size.w/2, self.size.h * 0.45),parent=self)            

        self.moving_bubble = SpriteNode('emj:White_Circle') 

        self.run_action(A.repeat(A.sequence(A.call(self.move_bubble), A.wait(1)), 0))

    def move_bubble(self):
        self.moving_bubble.alpha=1

        self.new_pos = (
            random.randrange(
                30, self.size.w - 30), 
            random.randrange(
                30, self.size.h - 30))
        self.moving_bubble.position = self. new_pos
        self.rules_node.add_child(
            self.moving_bubble)

        self.moving_bubble.run_action(
            A.repeat(
                A.sequence(
                    A.fade_to(0, 1.5), A.fade_to(1, 1)), 0))    

    def touch_began(self, touch):
        if touch.location in self.back.frame:
            self.dismiss_modal_scene()

class Settings(Scene):
    def setup(self):

        self.presses = 2
        self.times_dict = {
            1: 3, 2: 10, 3: 40}

        self.level_choice = 'Normal'

        self.time_choice = '10'

        self.settings_node = Node(parent=self)

        self.settings_bg = SpriteNode(position=self.size/2, color='black', size=self.size, alpha=1, parent=self.settings_node)  

        self.inc_time = SpriteNode(
            'iow:arrow_up_b_256', position= (self.size.w/2, self.size.h *0.65), scale=0.50, parent=self.settings_node) 

        self.dec_time = SpriteNode(
            'iow:arrow_down_b_256', position= (self.size.w/2, self.size.h *0.35), scale=0.50, parent=self.settings_node)    

        self.back_btn = SpriteNode('iow:ios7_redo_outline_32', position=(self.size.w * 0.10, self.size.h * 0.95), parent=self.settings_node)

        self.settings_label = LabelNode('Settings', ('Marker Felt', 30), position=(self.size.w/2, self.size.h * .92), parent=self.settings_node)

        self.time_label = LabelNode('Time', ('Marker Felt', 30), position=(self.size.w/2, self.size.h * 0.55), parent=self.settings_node)               
        self.level_c_label = LabelNode('Level',     ('Marker Felt', 30), position=(self.size.w/2, self.size.h * 0.20), parent=self.settings_node)   

        self.level_label = LabelNode(f'{self.level_choice}',     ('Marker Felt', 30), position=(self.size.w/2, self.size.h * 0.15), parent=self.settings_node)  

        #self.lvl_label = LabelNode(f'{}',     ('Marker Felt', 30), position=(self.size.w/2, self.size.h * 0.15), parent=self.settings_node)                                                
        self.time_choice_label = LabelNode(f'{self.time_choice}',     ('Marker Felt', 30), position=(self.size.w/2, self.size.h/2), parent=self.settings_node)              

        self.moving_bubble = SpriteNode('emj:White_Circle') 
        self.run_action(A.repeat(A.sequence(A.call(self.move_bubble), A.wait(1)), 0))

    def move_bubble(self):
        self.moving_bubble.alpha=1

        self.new_pos = (
            random.randrange(
                30, self.size.w - 30), 
            random.randrange(
                30, self.size.h - 30))
        self.moving_bubble.position = self. new_pos
        self.settings_node.add_child(
            self.moving_bubble)

        self.moving_bubble.run_action(
            A.repeat(
                A.sequence(
                    A.fade_to(0, 1.5), A.fade_to(1, 1)), 0))

    def touch_began(self, touch):
        if touch.location in self.inc_time.frame:

            self.presses += 1
            if self.presses == 4:
                self.presses = 1

            if self.presses == 1:
                self.level_choice = 'Hard'
                self.level_label.text = f'{self.level_choice}'                          
            elif self.presses == 2:
                self.level_choice = 'Normal'
                self.level_label.text = f'{self.level_choice}'                                                  
            else:
                self.level_choice = 'Easy'
                self.level_label.text = f'{self.level_choice}'                                          

        for key, value in self.times_dict.items():
            if key <= self.presses:
                self.time_choice = value
                self.time_choice_label.text = f'{self.time_choice}'         

        if  touch.location in self.back_btn.frame:
            self.sp.timer_value = self.time_choice

            self.dismiss_modal_scene()              

class StartPage(Scene):
    def setup(self):

        self.start_page_music = sound.play_effect('TappyTapIntro.wav', volume= 0.10)
        self.start_page_music.looping = True

        self.timer_value = 0

        self.start_page_node = Node(parent=self)
        self.start_page_bg = ShapeNode(ui.Path.rect(0, 0, self.size.w, self.size.h))
        self.start_page_bg.position=self.size/2
        self.start_page_bg.color='black'
        self.start_page_bg.alpha=1
        self.start_page_node.add_child(
            self.start_page_bg) 
        self.settings_btn = SpriteNode('iow:gear_a_24',
        position=(self.size.w * 0.10, self.size.h * 0.95), parent=self.start_page_node)
        self.rules_btn = SpriteNode('iow:help_circled_24', position=(self.size.w * 0.10, self.size.h * 0.9), parent=self.start_page_node)
        self.play_btn = SpriteNode('iow:ios7_play_32', position=(self.size.w * 0.10, self.size.h * 0.85), parent=self.start_page_node)
        self.tap = LabelNode('TappyTap', font=('MarkerFelt-Wide', 50), position=(self.size/2), alpha=2, parent=self.start_page_node)
        self.moving_bubble = SpriteNode('emj:White_Circle') 

        self.run_action(A.repeat(A.sequence(A.call(self.move_bubble), A.wait(1)), 0))

        self.present_modal_scene(Intro())

    def move_bubble(self):
        self.moving_bubble.alpha=1

        self.new_pos = (
            random.randrange(
                30, self.size.w - 30), 
            random.randrange(
                30, self.size.h - 30))
        self.moving_bubble.position = self. new_pos
        self.start_page_node.add_child(
            self.moving_bubble)

        self.moving_bubble.run_action(
            A.repeat(
                A.sequence(
                    A.fade_to(0, 1), A.fade_to(1, 1)), 0))

    def touch_began(self, touch):
        # --- Tap Me Btn ---
        if touch.location in self.play_btn.frame:
            sound.stop_all_effects()
            bg_music = sound.play_effect('TappyBeat.wav', volume=0.12)
            bg_music.looping = True         
            self.main.start_time = True

            self.main.timer_value = self.timer_value
            self.main.timer_amount_label.text = f'{self.main.timer_value}'
            self.dismiss_modal_scene()  

        if touch.location in self.settings_btn.frame:


            set.sp = self
            self.present_modal_scene(set)   

        if touch.location in self.rules_btn.frame:
            rl.sp = self
            self.present_modal_scene(rl)        

class MainScene (Scene):
    def setup(self):
        self.root_node = Node(parent=self)
        self.root_node.alpha=1
        self.game_over = False
        self.start_time = False
        self.timer_value = 15
        self.tap_count = 0
        self.frame_counter = 0
        self.seconds_past = 0
        self.points = 0
        self.highscore = self.load_highscore()
        self.color_list = ['#63ebff', '#71ff7e', '#ff44d6', 'orange', '#ffd174', 'yellow', '#ff40d5', '#00a200', '#3243ff', '#ba00ba', '#cbff55', '#5cbfff']        
        self.background_color = random.choice(self.color_list)

        sp.main = self
        self.present_modal_scene(sp)

        # --- Sprites ---
        self.bubble_radius = 30
        self.bubble_diameter = self.bubble_radius * 2

        self.bubble_pos = (random.randint(30, self.size.w - 30), random.randint(30, self.size.h - 30))

        self.bubble = SpriteNode('emj:White_Circle', position=self.bubble_pos, size=(self.bubble_diameter, self.bubble_diameter), 
        z_position=1, parent=self.root_node)

        self.vanish_bubble = SpriteNode('emj:White_Circle', position=self.bubble_pos, size=(self.bubble_diameter, self.bubble_diameter),
        z_position=1, parent=self.root_node)

        self.fader_bubble = SpriteNode('emj:White_Circle', position=self.bubble_pos, size=(self.bubble_diameter, self.bubble_diameter),
        z_position=1, parent=self.root_node)                                
        self.extra_time = SpriteNode('emj:Hourglass_1')
        self.extra_time.position = random.randrange(30, self.size.w - 30), random.randrange(30, self.size.h - 30)       

        self.replay_btn = SpriteNode('iow:ios7_refresh_empty_256', position=(-15, self.size.h * 0.2), scale=0.25, alpha=0.8)

        # --- Labels ---    
        self.label_color = 'white'  
        self.label_alpha = 0.8

        self.title_label = LabelNode('Tappy Tap', font=('MarkerFelt-Wide', 28), position=(self.size.w/2, self.size.h * .94), color=self.label_color, alpha=self.label_alpha, parent=self)

        self.timer_label = LabelNode('Timer', font=('MarkerFelt-Wide', 28), position=(self.size.w/2, self.size.h *0.07), color=self.label_color, alpha=self.label_alpha, parent=self.root_node)

        self.timer_amount_label = LabelNode(f'{self.timer_value}', font=('MarkerFelt-Wide', 20), position=(self.size.w/2, self.size.h *0.04), color=self.label_color, alpha=self.label_alpha, parent=self.root_node)

        self.tap_amount_label = LabelNode(f'{self.tap_count}', font=('MarkerFelt-Wide', 150), position=(self.size/2), color=self.label_color, alpha=self.label_alpha, parent=self.root_node)

        self.vanish_score = LabelNode('+5', font=('MarkerFelt-Wide', 40), position=(self.size/2), color=self.label_color, alpha=self.label_alpha, 
        z_position=1)

        self.points_label = LabelNode(f'{self.points}', ('MarkerFelt-Wide', 45), position=(self.size.w/2, self.size.h * .65), parent=self.root_node)    

        self.high_score_label = LabelNode('High Scores', font=('MarkerFelt-Wide', 23), position=(self.size.w/2, 0), color=self.label_color, alpha=self.label_alpha)

        self.show_highscore = LabelNode(str(self.highscore), font=('MarkerFelt-Wide', 23), position=(self.size.w/2, 0), color=self.label_color, alpha=self.label_alpha)

    def new_game(self): 
        self.remove_all_actions()
        self.setup()
        self.start_time = True
        self.dismiss_modal_scene()

    def spawn_time(self):
        self.root_node.add_child(self.extra_time)

    def remove_time(self):
        self.extra_time.remove_from_parent()

    def white_bg(self):
        self.background_color = 'white'

    def red_bg(self):
        self.background_color = 'red'   

    def load_highscore(self):
        try:
            with open('.TappyTapHighscore', 'r') as f:
                return int(f.read())
        except:
            return 0                

    def save_highscore(self):       
        if self.tap_count > self.highscore:
            with open('.TappyTapHighscore', 'w') as f:
                f.write(str(self.tap_count))
            self.highscore = self.tap_count 

    def did_change_size(self):
        pass

    def update(self):

        self.frame_counter += 1
        if self.frame_counter >= 60 and self.start_time == True:
            self.seconds_past += 1
            if self.timer_value <= 0:
                self.timer_value = 0
            else:
                self.timer_value -= 1
                self.timer_amount_label.text = f'{self.timer_value}'
                self.frame_counter = 0

        if self.timer_value == 0:
            self.game_over = True
            self.bubble.remove_from_parent()
            self.root_node.add_child(
                self.high_score_label)
            self.save_highscore()
            self.load_highscore()
            self.show_highscore.text=str(
                self.highscore)
            self.root_node.add_child(
                self.show_highscore)

            self.high_score_label.run_action(
                A.move_to(self.size.w/2, self.size.h * 0.90, 3, TIMING_ELASTIC_OUT))

            self.show_highscore.run_action(
                A.sequence(
                    A.wait(0.5), 
                    A.move_to(self.size.w/2, self.size.h * 0.85, 3, TIMING_ELASTIC_OUT)))               
            self.root_node.add_child(
                self.replay_btn)    

            self.replay_btn.run_action(
                A.move_to(self.size.w/2, self.size.h * 0.2, .5, TIMING_EASE_OUT))

        if self.seconds_past % 4 == 0 and self.game_over == True:
            self.run_action(
                A.repeat(
                    A.sequence(
                        A.call(self.red_bg), A.wait(4), A.call(self.white_bg), A.wait(4)), 0))

    def touch_began(self, touch):
        # --- Touch Bubble ---
        if abs(self.bubble.position - touch.location) <= self.bubble_radius and self.game_over == False:

            self.points += 5
            self.tap_count += 1
            self.background_color = random.choice(self.color_list)
            self.new_x = random.randrange(30, self.size.w - 30)
            self.new_y = random.randrange(30, self.size.h - 30)             
            self.tap_amount_label.font = ('MarkerFelt-Wide', 200)
            self.tap_amount_label.alpha = 1
            self.tap_amount_label.text = f'{self.tap_count}'
            self.points_label.text=f'{self.points}'
            self.vanish_score.alpha=1
            self.vanish_score.scale=1
            self.vanish_bubble.alpha=1
            self.fader_bubble.alpha=1    
            self.fader_bubble.scale=1       
            self.bubble.position = (self.new_x, self.new_y)

            self.vanish_bubble.position = touch.location
            self.fader_bubble.position = touch.location

            self.vanish_score.position = touch.location

            self.root_node.add_child(self.vanish_score)

            sound.play_effect('digital:Tone1', pitch=2, volume=0.6)

            self.vanish_bubble.run_action(
                A.sequence(
                    A.fade_to(0, 0.3)))
            self.fader_bubble.run_action(
                A.sequence(
                    A.group(
                        A.scale_to(0.0, 1), A.move_by(random.randrange(-20, 20), 200, 1, TIMING_EASE_OUT), A.fade_to(0, 1))))

            self.vanish_score.run_action(
                A.sequence(
                    A.group(
                        A.scale_to(2, 1), A.move_by(random.randrange(-20, 20), 200, 1, TIMING_EASE_OUT), A.fade_to(0, 2))))

            if self.tap_count % 20 == 0 and self.tap_count != 0:

                if self.tap_count > 50:
                    self.timer_value += 7
                else:
                    self.timer_value += 10
                    sound.play_effect(
                        'arcade:Powerup_2', volume=0.2)

            if self.tap_count % 50 == 0:
                self.run_action(
                    A.sequence(
                        A.wait(random.randint(0, 4)), A.call(self.spawn_time), A.wait(1), A.call(self.remove_time)))

        # --- Extra Time Btn    
        if touch.location in self.extra_time.frame: 
            self.extra_time.remove_from_parent()    
            self.timer_value += 5   

        # --- Replay Btn ---    
        if touch.location in self.replay_btn.frame:
            self.root_node.remove_from_parent()
            self.new_game()

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        self.tap_amount_label.font = ('MarkerFelt-Wide', 150)   
        self.tap_amount_label.alpha = 0.8

    def pause(self):
        sound.stop_all_effects()

    def resume(self):
        if self.presented_scene == sp:
            sound.play_effect('TappyTapIntro.wav', 0.10)
        else:
            sound.play_effect('TappyBeat.wav', volume=0.10)
            sound.looping = True        

    def stop(self):
        sound.stop_all_effects()


tro = Intro()
rl = Rules()
set = Settings()
sp = StartPage()        
main = MainScene()      

if __name__ == '__main__':
    run(main, PORTRAIT, show_fps=False)

resserone13

@JonB Check out the code I posted. You’ll see how are used the same bubble animation to animate the bubble in three scenes.

resserone13

@JonB i posted the code. I would appreciate any pointers you can give me. I’m sure there a a bunch of repetitive code that should be functions. I’m not to sure how to go about it cuz they rely on the scene module. If you have some time can you make some suggestions and maybe give some examples. I would really appreciate it. Thanks

mikael

@resserone13, @JonB is an absolute hero and might come back with something, but in general dumping several screenfuls of code to a forum post and asking someone to "make it better" is unlikely to get you the help you are looking for.

For best results, you need to take the time to think of specific questions and to pull out tight (short) examples to help discuss them.

cvp

@resserone13 A little detail, you should put a standard sound as default because the script stops immediately if you don't have your sound as local file.

cvp

@mikael said:

@JonB is an absolute hero

At least!

resserone13

@mikael I did ask. I was in regards to scenes. It’s a couple comments up. I was asking how you get one scene that’s about three scenes layered over the main seem to update the main seen and I didn’t understand the example he gave. it seem like the same example which he gave before which I I got it to work but just for one screen layered over the main screen? This was asked above. Then he asked me to post the code.

JonB

I'll take.l a look, but a few things I will say...

Presenting a modal scene from within setup sounds like a supremely bad idea.
Especially if it is not the very last part of setup. If your start screen is trying to change any of your main scene settings, they will be immediately overriden by whatever you have in setup after the present modal scene is called.

You might consider whether the main scene SHOULD maintain copies of the parameters that you want to adjust in the start menu -- or if those should be attributes of your menu scene, which main scene can refer to by accessing those variables directly.

Note also that -- I think, but easy to verify -- whenever you re-present a scene, setup is called again. So, if you are trying to persist settings like speed, etc, across multiple runs, they should not be initialized in setup (instead, use __init__)

resserone13

@JonB Thank you for the advice. I’m going to try to work this in. I am also going to review all of my post to make sure I haven’t missed any advice. I really appreciate you guys helping me. I’ve seen some things you guys have worked on on github and it is much above my level. I appreciate you guys taking the time to help me. I feel it’s a privilege to be helped by people who know so much. Thank you very much @mikael @ccc @cvp.