locked
Best way to visually switch between game screens? RRS feed

  • Question

  • Let's say you have a game that consists of a: splash, menu, gameplay and gameover-screen. I guess these are the most common "game screens" and somehow we all need to visually switch between these.

    As I see it there are two ways of doing this:

    1. 100% in code. You simply add/remove UserControls from your main LayoutRoot dynamically
      1. Good about this approach
        1. You have 100% control over what's going on at any time.
      2. Bad about this approach
        1. If you have a designer working in Blend, or you work in Blend yourself, you don't get a very good picture of the game. You can't see in Blend, visually, what shown in the different "game states".
        2. You can easially get a lot of "spaghetti code" that can be pretty complex, just for the purpose of switching between screens.
    2. Using VisualStates in Blend
      1. Good about this approach
        1. I guess this must be the "right" way, as you use the tools fully.
        2. You can easially make VisualStates within Blend and apply transitions between screens
      2. Bad about this approach
        1. You can't do "all" by doing it this way, sometimes VisualStates just isn't enough, or at least I have run into problems sometimes, maybe it's just me not good enough in Blend :)


    So, I just want to hear how you guys are overcoming this very common scenario?

    :)

    Thursday, June 4, 2009 3:01 AM

Answers

  •  Hi Qbus

    In Squarepeg,  I manage the switching between game screens 100% in code.  I have various different Silverlight User Controls, representing for example:

    - Layout Root / Main Menu
    - Game 'container'
    - Gameboard itself.

    Each UserControl is instantiated and added as a child to the layout root.  It raises its own events to indicate when it has closed, or in some cases when something has changed that means the parent display needs updating.  (for example, the gameboard only partially obscures the game container.  The game container displays the score, current level, etc. so it needs to be told when these have changed)

    I have static 'appSettings' and Functions classes too; these are most useful for the sharing of information and code between the various UserControls. (e.g. sound effects volume, common functions to show/hide xaml, username storage, etc.)   This avoids lots of messy 'chaining' of events and variables along the various parent-child relationships.

    I also have a UserControl for display of modal-style dialog boxes, questionboxes and 'please-wait'-style notifications.  The modal effect is achieved by using a partially transparent box that completely covers the window.

    Hope this answers your question,

    Carlos

    Thursday, June 4, 2009 4:42 AM
  • I do the same thing in Perenthia, each user control represents the screen view or state. I have a static manager class to aid in switching states.

    Thursday, June 4, 2009 9:00 AM

All replies

  •  Hi Qbus

    In Squarepeg,  I manage the switching between game screens 100% in code.  I have various different Silverlight User Controls, representing for example:

    - Layout Root / Main Menu
    - Game 'container'
    - Gameboard itself.

    Each UserControl is instantiated and added as a child to the layout root.  It raises its own events to indicate when it has closed, or in some cases when something has changed that means the parent display needs updating.  (for example, the gameboard only partially obscures the game container.  The game container displays the score, current level, etc. so it needs to be told when these have changed)

    I have static 'appSettings' and Functions classes too; these are most useful for the sharing of information and code between the various UserControls. (e.g. sound effects volume, common functions to show/hide xaml, username storage, etc.)   This avoids lots of messy 'chaining' of events and variables along the various parent-child relationships.

    I also have a UserControl for display of modal-style dialog boxes, questionboxes and 'please-wait'-style notifications.  The modal effect is achieved by using a partially transparent box that completely covers the window.

    Hope this answers your question,

    Carlos

    Thursday, June 4, 2009 4:42 AM
  • I do the same thing in Perenthia, each user control represents the screen view or state. I have a static manager class to aid in switching states.

    Thursday, June 4, 2009 9:00 AM
  •  Ok great to hear, so doing this in code seems to be the most used way of doing this.

    @lionsguard: "I have a static manager class to aid in switching states." Do you mind sharing some of this code here? Or just give an example?

     

    Thursday, June 4, 2009 2:40 PM
  • Yeah, sounds more complex to describe it that actually use it :)

    I have two these two interfaces defined:

    public interface IScreen
    {
      UIElement Element { get; }
    }
    
    public interface IScreenHost
    {
      void SetScreen(IScreen screen);
    }
    
    Then, the UserConrols that are to be screens just implement the IScreen interface and return themselves as the UIElement:
    public partial class PlayScreen : UserControl, IScreen
    {
      public UIElement Element { get { return this; } }
    }
    

    The IScreenHost is the container canvas for the screen (This control is placed on the Page surface):

    public partial class Host : UserControl, IScreenHost
    {
      public void SetScreen(IScreen screen)
      {
        this.LayoutRoot.Children.Clear();
        this.LayoutRoot.Children.Add(screen.Element);
      }
    }
    

    And I use this class to handle switching of the screens.

    public static class ScreenManager
    {
      private static IScreenHost _host;
    
      public static void SetHost(IScreenHost host)
      {
        _host = host;
      }
    
      public static void SetScreen(IScreen screen)
      {
        _host.SetScreen(screen);
      }
    }
    

    In my Page.xaml.cs class, in the Loaded event handler I make this call to set up the host:

    ScreenManager.SetHost(this.host);
    

    When I want to change screens or set a new screen as the default I just make this call:

    ScreenManager.SetScreen(new PlayScreen());
    

    Friday, June 5, 2009 9:48 PM
  •  Thanks for sharing :)

    I see, that IS pretty simple, but seems effective. One could extent this so IScreen could have some kind of "Intro" and "Outtro", for instance if you wanted it to fade in/out or what not.

    Thanks again.

    Sunday, June 7, 2009 11:41 AM
  • I just want to +1 on using code to switch between screens instead of using VisualStates.  In the original Vector Space, I had all the controls on the Page at once, which got messy.  For TowerOfBabble and Vector Space Armada, I did what others described, where every "screen" is just a user control, and I have a method in a control class that handles all the screen setup and take down.  It is much easier to maintain that way.

    In tower of Babble I have a FadeIn and FadeOut animation on a storyboard on my Page, and oldScreen and newScreen instance variables.  I set the targets on FadeOut to oldScreen and on FadeIn to newScreen.  On FadeOutCompleted oldScreen is removed and set to null and the targets are cleared on FadeOut.  No interfaces were needed.

    Thursday, July 2, 2009 4:34 AM
  • I just want to +1 on using code to switch between screens instead of using VisualStates.  In the original Vector Space, I had all the controls on the Page at once, which got messy.  For TowerOfBabble and Vector Space Armada, I did what others described, where every "screen" is just a user control, and I have a method in a control class that handles all the screen setup and take down.  It is much easier to maintain that way.

    In tower of Babble I have a FadeIn and FadeOut animation on a storyboard on my Page, and oldScreen and newScreen instance variables.  I set the targets on FadeOut to oldScreen and on FadeIn to newScreen.  On FadeOutCompleted oldScreen is removed and set to null and the targets are cleared on FadeOut.  No interfaces were needed.

    That's exactly my experience too. In Bubbles and Balloon Mayhem I have each "screen" as a UserControl, but all the UserControls are on the Page.xaml. I switch between them with VisualStates. I can see now that that, very quick, becomes way to complex control and develop on in some scenarioes, thats why I created this thread. Thanks for you input guys, seems like the "best" way is to handle switching of screens in code. This rise another question, when do you guys then use VisualStates? Or do you just discard them totally? :)
    Thursday, July 2, 2009 7:56 AM
  • I too have each screen as a UserControl that's created and scoped in the custom Application class.  My Application class has a method called ChangePage that takes an enumerated type that contains the various pages available.  This makes the code a little cleaner.

     I think that a benefit of using different UserControls is that it would be easier to reuse one of the pages, for example a chat lobby page, in another application.

    Thursday, July 2, 2009 8:02 AM
  • This rise another question, when do you guys then use VisualStates? Or do you just discard them totally? :)

    I don't.  Since I'm not developing any controls I expect to distribute, or even use as templatable controls within the app, then I don't see the advantage over just plain old Storyboard's.

    Thursday, July 2, 2009 8:53 AM
  •  Actually, I switch between screens in make some animations in UserControls, and so, all the content is in the XAML page. But that you said in this post seems very interessant and more powerful. If someone has an article or a tutorial about that.

     

    Thank you :)

    Friday, July 3, 2009 4:26 AM
  • In my games, every screen is a UserControl, which implements an interface "IScreen". I have a MainScreen UserControl, which is invisible, which displays the current screen and handles switching between the screens.

    The IScreen interface contains an event "OnSwitchScreen". The MainScreen subscribes to this event when a new screen is created with the new keyword. The screen itself invokes this event when it needs to switch to another screen. I use an enumerated type to communicate the destination, (ie, main screen display, highscores, instructions) and this enumerated type is translated to a new <NextScreen>() in a factory function. This way I don't need to worry about how the screenswitch is handled while I am creating a screen. The OnSwithScreen event constains the screen destination, and optionally the level and score of the player, for the case that you want to communicate this information to the highscore screen.

    Friday, July 3, 2009 4:59 AM
  • Why does your screen extend UserControl?  Shouldn't you use something that has children?  I'm currently working on something similar, and have everything extending Panel.

    Saturday, April 16, 2011 5:57 PM
  • Hi,

    Every screen has its own XAML, that's why it is a UserControl. I don't know about other controls having that same advantage, my method works for me, but I'm open for suggestions.

    Monday, April 18, 2011 12:48 PM
  • How do you give each user control its own XAML?  Is there a load from method in user control?

    Edit:  It just occurred to me how stupid a question that is...  I assume you create a new xaml control and do the implementation of element in the code associated with the xaml.

    Thursday, April 21, 2011 12:17 AM
  • "I assume you create a new xaml control and do the implementation of element in the code associated with the xaml."

     

    Correct. And it is not called a "xaml control", but a "UserControl" :)

    Thursday, April 21, 2011 7:34 AM