Forum Archive

Scene transitions

Oscar

With the new type of Scenes with Nodes instead of using Layers or implementing draw(), what are the options when building an app with multiple Scenes?

Before many used the MultiScene class (https://gist.github.com/omz/4059061). When no longer using draw() this seems less natural.

I've also seen suggestions of calling Scene.run() multiple times, but that show the swipe in from bottom transitions and is stacking the Scenes on top of each other.

There's also the Scene.present_modal_scene() as shown in the BrickBreaker example. It is very nice when using a modal Scene, especially when you only want it to cover part of the screen. But it is not really switching from one Scene to the next.

In iOS's SceneKit there is the SKTransition class that is used to transition from one SKScene to another using SKView presentScene. Even without any fancy transitions I don't really know the preferred way to do this in pythonista.

Let's say I have five Scenes in a game:
- MainMenuScene
- SettingsScene
- CreditsScene
- PlayScene
- NewHighScoreScene

The possible transitions:
MainMenu <-> Settings
MainMenu <-> Credits
MainMenu <-> PlayScene -> NewHighScoreScene -> MainMenu

Let's say I would want to build that. Can I do that with normal Scenes, or do I need to build something myself? Any ideas are very welcome.

Oscar

OK, now I have an example of what I'm thinking about: https://gist.github.com/offe/95d9189cc62bb9d268e7

It's the five Scenes put together into probably the most pointless game of all time.

The main menu shows three buttons and a high score. On the Credits screen and Settings screen you can only go back to the main menu. If you press Play the game starts. The game consists of a button labeled "+1" and another labeled "Game Over". Every time you tap "+1" you get a point. When you press "Game Over" the game is over. If you achieve high score the "New High Score" screen is shown. Then you are back in the Main Menu.

I went with the "MultiScene" construction, but the class is called SceneSwitcher to separate it from the earlier MultiScene calss. Every time a scene is shown all its nodes are moved into the SceneSwitcher, and when it is replaced the nodes are moved back.

There are a few limitations to this strategy:
- If the Scenes change background color after setup the background color is not changes.
- If scenes add nodes to itself these will not show up on the screen (this is why I only change children of top level nodes in the example)
- There are more I'm sure...

I'm not too happy with how this turned out. I would have liked to link together a few normal Scenes. Does anyone have a better idea how to do this?

I feel like I have three options here:
1. Continue with this hack
1. Build something more elaborate, that does not use multiple Scenes
1. Wait for an addition in the scene module that handles Scene transitions

Any ideas anyone?

JonB

The new scene module has

Scene.present_modal_scene(other_scene)
Present another scene on top of this one. This can be useful for overlay menus etc. While the scene is being presented, it receives all touch events.

which seems to do what you want. dismiss_modal_scene when it is done

Oscar

Thanks JonB, but I don't think that's what I'm after. I would like to string together a couple of normal Scenes into a larger app. Some of those scenes might want to present a modal scene itself. If I use that method to switch between scenes I would not be able to display real modal scenes.

I've continued a little bit on the gist I shared in the previous post. I realised that Scenes are Nodes, and that made things a little bit cleaner. I even added fade through black or white transitions and slide transitions between Scenes.

The SceneSwitcher class is actually starting to look useful. I'm having some network problems with my iPad. I'll try to share the code in a gist tomorrow.

ccc

I too struggle to understand modal scenes... Two questions on the snippet below:

  1. Is there a way to make the OverlayScene opaque so the text from the MainScene does not make it unreadable?
  2. Why don't the background_color settings work?
import scene

class OverlayScene(scene.Scene):
    def setup(self):
        #self.background_color = 'midnightblue'  # EDIT: this line commented out and next line added
        scene.SpriteNode(color='midnightblue', parent=self, size=self.size).anchor_point=(0,0)
        scene.LabelNode(self.__class__.__name__, position=(self.size[0]/2, self.size[1]*0.9),
                            font=('Helvetica', self.size[0]/20), parent=self)

    def touch_ended(self, touch):
        self.dismiss_modal_scene()

class MainScene(scene.Scene):
    def __init__(self):
        scene.run(self)

    def setup(self):
        self.background_color = 'black'
        scene.LabelNode(self.__class__.__name__, position=(self.size[0]/2, self.size[1]*0.9),
                            font=('Helvetica', self.size[0]/20), parent=self)
        self.present_modal_scene(OverlayScene())

    def touch_ended(self, touch):
        if not self.presented_scene:
            self.present_modal_scene(OverlayScene())

if __name__ == '__main__':
    MainScene()
Oscar

@ccc, you should have a look at game_menu.py in the Games examples. The class MenuScene is the modal Scene used in all the game examples. The background color of the modal scene is ignored. Instead you need to create your own background. The MenuScene has a nice rounded rectangle with a border implemented with a ShapeNode. It even has a shadow.

The easiest way is probably to simply create a SpriteNode with a color but no texture.

ccc

Thanks @Oscar ! I inserted a one line change in the code above. Of course, @omz version is much slicker😕

ccc

See the comments on the gist... I removed SceneSwitcher and simplified other logic. NewHighScoreScene is not yet working...

The possible transitions:
MainMenu <-> Settings
MainMenu <-> Credits
MainMenu <-> PlayScene -> NewHighScoreScene -> MainMenu

Could be rewritten as:

The possible transitions:
MainMenu <-> Settings
MainMenu <-> Credits
MainMenu <-> PlayScene  # if new high score then remove PlayScene and immediately show NewHighScoreScene
MainMenu <-> NewHighScoreScene

By this logic, instead of main() being run(PlayScene(MainMenuScene())) perhaps it should just be run(MainMenuScene()).

Repos are so much easier than gists ;-)

ccc

My SECOND comment on the gist has it all working. I thought that Scene.present_modal_scene() blocked the presenting scene until the presented scene was dismissed but it does not.

Oscar

Now I've added what I wanted from the beginning: Transitions

The new version of the code is here:
https://gist.github.com/offe/a58d34573d8f5c89743a

Thanks @ccc for teaching me to set LabelNodes' text properties instead of creating new ones. Very handy indeed.

There are now three (actually four) transitions:
- TransitionCrossFade (fade from the old to the new scene)
- TransitionFadeWithColor (fade through a color to the new scene)
- TransitionPush (sliding the new scene into view, while pushing out the old)
- TransitionImmediate (which is not really a transition at all, just a direct switch)

The whole thing is very much inspired by SKView of SpriteKit: https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKView/index.html#//apple_ref/occ/instm/SKView/presentScene:transition:

And the names of transitions are from SKTransitions: https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKTransition_Ref/index.html#//apple_ref/swift/cl/c:objc(cs)SKTransition

It seems to me to work pretty well now, so I will go on with what I wanted to do from the beginning: build something. If anyone sees something that does not work or will cause problems, please let me know. Any and all comments are welcome!

Oscar

I just made my first animated gif!

This is what the scene transitions in action looks like. The gif is just 10 fps, but on the device it is of course in full frame rate:

alt text

So that is five different Scenes put together.

The point of the experiment is to stitch together normal Scenes into a larger app. Right now the Scenes does not have to know anything about the SceneSwitcher until they use it to start the next Scene.

Webmaster4o

This is pretty cool, great job

mrcoxall

Am I wrong, or does the above code only work in the beta version of Pythonista, that has not yet been released yet?

Oscar

Yes, the Code is for the new Scene module. For the current version of Pyhonista the old MultiScene solution works very well.

mrcoxall

I came back to try this again, just to make sure it is still working before I try it with my students. When I use the current version of the original Pythonista and this: https://gist.github.com/offe/a58d34573d8f5c89743a, the app is just crashing on me now.

Is anyone else having this problem?

ccc

Scenes have changed a lot since those posts were written and now multi scene support is builtin.

See: scene.Scene.present_modal_scene() and scene.Scene.presented_scene.

mrcoxall

I am having a problem presenting the second scene with the present_modal_scene().
Does anyone have an example of the best practises using this?

This is what I have so far:
(note: I am using a UI.view since I want to place it in the PythonistaAppTemplate and then into Xcode)

# for use with https://github.com/omz/PythonistaAppTemplate

from scene import *
import ui

class FirstScene (Scene):
    def setup(self):
        self.background_color = 'midnightblue'
        self.ship = SpriteNode('spc:PlayerShip1Orange')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def touch_began(self, touch):
        # question?
        # how do you get to the second scene? 
        self.present_modal_scene(my_second_scene)

class SecondScene (Scene):
    def setup(self):
        self.background_color = '#704414'
        self.ship = SpriteNode('spc:EnemyGreen2')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def touch_began(self, touch):
        pass

my_scene = FirstScene()
my_second_scene = SecondScene()
# Instead of...
# run(MyScene())

# ..use:
main_view = ui.View()
scene_view = SceneView(frame=main_view.bounds, flex='WH')
main_view.add_subview(scene_view)
scene_view.scene = my_scene
main_view.present(hide_title_bar=True, animated=False)
omz

@mrcoxall Your code works for me, but note that modal scenes don't draw any background (i.e. the background_color attribute is ignored). You might want to use a colored SpriteNode to prevent the first scene from shining through. This behavior is intentional because a common use case for present_modal_scene is to present a menu overlay with transparent background (as in the included game examples).

mrcoxall

So omz was correct and the background was the first problem.
When I do it for just a single scene, it all seems to work fine.

My next problem is that I tried to make it move from one scene to a second.
Problem is I am getting a "Value error: inconsistent Node hierarchy", when I try to move from the second scene back to the first one.

The good news is that I placed it in Xcode and the App template works great.
Here is my code:

# for use with https://github.com/omz/PythonistaAppTemplate

from scene import *
import ui

class MainScene (Scene):
    def setup(self):
        # this is the starting scene, for ui.View
        # all other scenes will come from

        self.background_color = 'black'
        self.present_modal_scene(first_scene)


class FirstScene (Scene):
    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.ship = SpriteNode('spc:PlayerShip1Orange')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def update(self):
        pass
    #x, y, z = gravity()
    #pos = self.ship.position
    #pos += (x * 15, y * 15)
    # Don't allow the ship to move beyond the screen bounds:
    #pos.x = max(0, min(self.size.w, pos.x))
    #pos.y = max(0, min(self.size.h, pos.y))
    #self.ship.position = pos

    def touch_began(self, touch):
        # question?
        # how do you get to the second scene?
        #self.dismiss_modal_scene()
        self.present_modal_scene(second_scene)

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        pass


class SecondScene (Scene):
    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'green')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.ship = SpriteNode('spc:EnemyGreen2')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def touch_began(self, touch):
        self.present_modal_scene(first_scene)
#pass


main_scene = MainScene()
first_scene = FirstScene()
second_scene = SecondScene()
# Instead of...
# run(MyScene())

# ..use:
main_view = ui.View()
scene_view = SceneView(frame=main_view.bounds, flex='WH')
main_view.add_subview(scene_view)
scene_view.scene = first_scene
main_view.present(hide_title_bar=True, animated=False)
omz

@mrcoxall Use dismiss_modal_scene instead of present_modal_scene to get back from the second scene to the first one.

ccc
from scene import *


class FirstScene(Scene):
    def setup(self):
        # add white background
        SpriteNode(anchor_point=(0, 0), color='white', parent=self,
                   size=self.size)
        self.ship = SpriteNode('spc:PlayerShip1Orange', parent=self,
                               position=self.size / 2)

    def touch_began(self, touch):
        self.present_modal_scene(SecondScene())


class SecondScene(Scene):
    def setup(self):
        # add green background
        SpriteNode(anchor_point=(0, 0), color='green', parent=self,
                   size=self.size)
        self.ship = SpriteNode('spc:EnemyGreen2', parent=self,
                               position=self.size / 2)

    def touch_began(self, touch):
        self.dismiss_modal_scene()


if __name__ == '__main__':
    scene_view = SceneView()
    scene_view.scene = FirstScene()
    scene_view.present(hide_title_bar=True, animated=False)
mrcoxall

Thanks again to everyone for their help, I am getting close to a "scene solution" I can use.

The problem I have now is, I would like to use a timer, so that after a second it automatically moves to the next scene. I would like to use it for a splash screen at the beginning. Because it is modal though, the scene is still running in the background.

Is there any way to not have it modal or to actually really completely remove the scene, so it is not running and then go to the new one? There will be some scenes I will only ever use once, so removing them from memory would be the best.

# for use with https://github.com/omz/PythonistaAppTemplate

from scene import *
import ui
import time

class FirstScene (Scene):

    # global variable to class
    start_time = None

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        # get starting time
        global start_time
        start_time = time.time() 

        self.ship = SpriteNode('spc:PlayerShip1Orange')
        self.ship.position = self.size / 4
        self.add_child(self.ship)

    def update(self):
        # move to new scene after 1 second
        # problem is it keeps happening, since it is modal
        # is there a way to actually really dispose 
        # of a scene and then move forward?

        current_time = time.time()
        if current_time - start_time > 1:
            #self.present_modal_scene(second_scene)
            pass

    def touch_began(self, touch):
        #self.dismiss_modal_scene()
        #self.present_modal_scene(second_scene)
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        if self.ship.frame.contains_point(touch.location):
            self.present_modal_scene(second_scene)


class SecondScene (Scene):

    # global variable to class
    start_time = None

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'green')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        # get starting time
        global start_time
        start_time = time.time()

        self.ship = SpriteNode('spc:EnemyGreen2')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def update(self):
        # move to new scene after 1 second
        current_time = time.time()
        if current_time - start_time > 1:
            #self.present_modal_scene(second_scene)
            pass

    def touch_began(self, touch):

        self.present_modal_scene(main_menu_scene)


class MainMenuScene (Scene):
    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'blue')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.ace = SpriteNode('card:ClubsA')
        self.ace.position = (683.0, 512.0)
        self.add_child(self.ace)

        self.king = SpriteNode('card:ClubsK')
        self.king.position = (683.0, 750.0)
        self.add_child(self.king)

        self.queen = SpriteNode('card:ClubsQ')
        self.queen.position = (683.0, 238.0)
        self.add_child(self.queen)

    def update(self):
        pass

    def touch_began(self, touch):
        #self.dismiss_modal_scene()
        #self.present_modal_scene(a_scene)
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        # move to new scenes
        if self.ace.frame.contains_point(touch.location):
            self.present_modal_scene(a_scene)
        elif self.king.frame.contains_point(touch.location):
            self.present_modal_scene(b_scene)
        elif self.queen.frame.contains_point(touch.location):
            self.present_modal_scene(c_scene)


class AScene (Scene):
    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.a_choise = SpriteNode('card:BackBlue1')
        self.a_choise.position = self.size / 2
        self.add_child(self.a_choise)

    def update(self):
        pass

    def touch_began(self, touch):
        self.dismiss_modal_scene()
        #self.present_modal_scene(b_scene)

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        pass


class BScene (Scene):
    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.ship = SpriteNode('card:BackGreen1')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def update(self):
        pass

    def touch_began(self, touch):
        self.dismiss_modal_scene()
        #self.present_modal_scene(c_scene)

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        pass


class CScene (Scene):
    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.ship = SpriteNode('card:BackRed1')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def update(self):
        pass

    def touch_began(self, touch):
        self.dismiss_modal_scene()
        #self.present_modal_scene(second_scene)

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        pass


first_scene = FirstScene()
second_scene = SecondScene()
main_menu_scene = MainMenuScene()
a_scene = AScene()
b_scene = BScene()
c_scene = CScene()
# Instead of...
# run(MyScene())

# ..use:
main_view = ui.View()
scene_view = SceneView(frame=main_view.bounds, flex='WH')
main_view.add_subview(scene_view)
scene_view.scene = first_scene
main_view.present(hide_title_bar=True, animated=False)
mrcoxall

The following is the best I have been able to come up with as a template for scene management. I have a timer for the fist scene. Unfortunately I cannot get one working for the second.

I am still looking for a "non-modal" way to present a scene or a way to completely remove a scene, so that it is no longer running.
Thanks again for any help.

# for use with https://github.com/omz/PythonistaAppTemplate

from scene import *
import ui
import time

class FirstScene (Scene):

    # global variable to class
    start_time = None

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        # get starting time
        global start_time
        start_time = time.time() 

        self.ship = SpriteNode('test:Pythonista')
        self.ship.position = self.size / 2
        self.ship.size = self.size
        self.add_child(self.ship)

    def update(self):
        # move to new scene after 2 second
        # problem is it keeps happening, since it is modal
        # is there a way to actually really dispose 
        # of a scene and then move forward?

        current_time = time.time()

        #global scene_moved_away_from
        if current_time - start_time > 2:
            self.present_modal_scene(second_scene)

    def touch_began(self, touch):
        #self.present_modal_scene(second_scene)
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        if self.ship.frame.contains_point(touch.location):
            self.present_modal_scene(second_scene)


class SecondScene (Scene):

    # global variable to class
    start_time = None

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'green')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        start_time = time.time()

        self.ship = SpriteNode('spc:EnemyGreen2')
        self.ship.position = self.size / 2
        self.add_child(self.ship)

    def update(self):
        # move to new scene after 2 second
        current_time = time.time()

        # have to comment out because get "max recursion error"
        # code keeps reloading first then second scene over and
        # over again, since time has lapsed
        #if current_time - start_time > 2:
            #self.present_modal_scene(second_scene)
            #pass

    def touch_began(self, touch):
        self.pause = True
        self.present_modal_scene(main_menu_scene)

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        pass


class MainMenuScene (Scene):

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'blue')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.ace = SpriteNode('card:ClubsA')
        self.ace.position = (683.0, 512.0)
        self.add_child(self.ace)

        self.king = SpriteNode('card:ClubsK')
        self.king.position = (683.0, 750.0)
        self.add_child(self.king)

        self.queen = SpriteNode('card:ClubsQ')
        self.queen.position = (683.0, 238.0)
        self.add_child(self.queen)

    def update(self):
        pass

    def touch_began(self, touch):
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        # move to new scenes
        if self.ace.frame.contains_point(touch.location):
            self.present_modal_scene(a_scene)
        elif self.king.frame.contains_point(touch.location):
            self.present_modal_scene(b_scene)
        elif self.queen.frame.contains_point(touch.location):
            self.present_modal_scene(c_scene)


class AScene (Scene):

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.blue_card = SpriteNode('card:BackBlue1')
        self.blue_card.position = self.size / 2
        self.add_child(self.blue_card)

    def update(self):
        pass

    def touch_began(self, touch):
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        # moving back to previous scene, so remove modal makes sense
        if self.blue_card.frame.contains_point(touch.location):
            self.dismiss_modal_scene()


class BScene (Scene):

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.green_card = SpriteNode('card:BackGreen1')
        self.green_card.position = self.size / 2
        self.add_child(self.green_card)

    def update(self):
        pass

    def touch_began(self, touch):
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        # moving back to previous scene, so remove modal makes sense
        if self.green_card.frame.contains_point(touch.location):
            self.dismiss_modal_scene()


class CScene (Scene):

    def setup(self):
        # add background color
        self.background = SpriteNode(color = 'white')
        self.background.size = self.size
        self.background.position = self.size / 2
        self.add_child(self.background)

        self.red_card = SpriteNode('card:BackRed1')
        self.red_card.position = self.size / 2
        self.add_child(self.red_card)

    def update(self):
        pass

    def touch_began(self, touch):
        pass

    def touch_moved(self, touch):
        pass

    def touch_ended(self, touch):
        # moving back to previous scene, so remove modal makes sense
        if self.red_card.frame.contains_point(touch.location):
            self.dismiss_modal_scene()


first_scene = FirstScene()
second_scene = SecondScene()
main_menu_scene = MainMenuScene()
a_scene = AScene()
b_scene = BScene()
c_scene = CScene()
# Instead of...
# run(MyScene())

# ..use:
main_view = ui.View()
scene_view = SceneView(frame=main_view.bounds, flex='WH')
main_view.add_subview(scene_view)
scene_view.scene = first_scene
main_view.present(hide_title_bar=True, animated=False)
ccc

If you want transitory scenes then create the main scene in your main program but then only create overlaying scenes when you actually need them. That is, do not create scenes in your main() if you want them to be transitory.

  • Try creating sceneA inside the body of the MainScene class.
  • Try creating sceneB inside the body of the sceneA class.
  • Try creating sceneC inside the body of the sceneB class.

As variables like "sceneC" fall out of scope, they can be garbage collected but those scenes that are defined in main() can not be garbage collected until main() ends.

See the code above where FirstScene.touch_begin() creates and displays a SecondScene. Then SecondScene.touch_begin() destroys self to go back to the FirstScene.

ccc

My "Pull Request"...

  • Uses self.presented_sceneto know if there is a modal scene above self.
  • Removes both class variables and global variables -- they are NOT the same thing.
  • Does a two second hop from 1st scene to 2nd scene and a two second hop from 2nd scene to 3rd scene without recursion issues.
  • Creates scenes on-the-fly when needed to allow them to be garbage collected once they have been closed.
  • Adds card_back_colorto allow one scene class to show card backs of different colors.
# for use with https://github.com/omz/PythonistaAppTemplate

from scene import *
import time


class FirstScene(Scene):
    def setup(self):
        # get starting time
        self.start_time = time.time()
        # add background color
        SpriteNode(anchor_point=(0, 0), color='white', parent=self,
                   size=self.size)
        self.ship = SpriteNode('test:Pythonista', anchor_point=(0, 0),
                               parent=self, size=self.size)

    def update(self):
        # move to new scene after 2 seconds
        if not self.presented_scene and time.time() - self.start_time > 2:
            self.present_modal_scene(SecondScene())

    def touch_began(self, touch):
        # self.present_modal_scene(SecondScene())
        pass

    def touch_ended(self, touch):
        if self.ship.frame.contains_point(touch.location):
            self.present_modal_scene(SecondScene())


class SecondScene(Scene):
    def setup(self):
        self.start_time = time.time()
        # add background color
        SpriteNode(anchor_point=(0, 0), color='green', parent=self,
                   size=self.size)
        self.ship = SpriteNode('spc:EnemyGreen2', parent=self,
                               position=self.size/2)

    def update(self):
        if not self.presented_scene and time.time() - self.start_time > 2:
            self.present_modal_scene(MainMenuScene())

    def touch_began(self, touch):
        self.present_modal_scene(MainMenuScene())


class MainMenuScene (Scene):
    def setup(self):
        # add background color
        SpriteNode(anchor_point=(0, 0), color='blue', parent=self,
                   size=self.size)

        self.ace = SpriteNode('card:ClubsA', parent=self, position=(683, 512))
        self.king = SpriteNode('card:ClubsK', parent=self, position=(683, 750))
        self.queen = SpriteNode('card:ClubsQ', parent=self, position=(683, 238))

    def touch_ended(self, touch):
        # move to new scenes
        if self.ace.frame.contains_point(touch.location):
            self.present_modal_scene(CardBackScene('blue'))
        elif self.king.frame.contains_point(touch.location):
            self.present_modal_scene(CardBackScene('green'))
        elif self.queen.frame.contains_point(touch.location):
            self.present_modal_scene(CardBackScene('red'))


class CardBackScene(Scene):
    def __init__(self, card_back_color='blue'):
        Scene.__init__(self)
        self.img_name = 'card:Back{}1'.format(card_back_color.title())

    def setup(self):
        # add background color
        SpriteNode(anchor_point=(0, 0), color='white', parent=self,
                   size=self.size)
        self.card = SpriteNode(self.img_name, parent=self,
                               position=self.size/2)

    def touch_ended(self, touch):
        # moving back to previous scene, so remove modal makes sense
        if self.card.frame.contains_point(touch.location):
            self.dismiss_modal_scene()


main_view = SceneView()
main_view.scene = FirstScene()
main_view.present(hide_title_bar=True, animated=False)
mrcoxall

Works great.
Thanks so much.

Patrick

PeterG

@ccc, just something I need , very nice indeed! I import a game, that for grand-son and daughter, and run it before the background cardimages are shown, meeaning I am on the way for an 4-level game ...
Next try, just using one of the marvallous available games , as next levels ..
.. Topscore files will be used for further interaction ..

Thanks to your example ... Helps a lot 😊 , happy OpaPeter