Showing posts with label game state management. Show all posts
Showing posts with label game state management. Show all posts

Friday, September 8, 2023

90.) Creating the Credits Screen for our Menu System

     Hello fellow game developers! In this blog post, we'll dive into the inner workings of the credits screen for our menu system. The credits screen is an essential component of many games, as it provides recognition to the talented individuals who contributed to the game's development. Let's take a closer look at the code and functionality of this CreditsScreen class.

Code in Full: 

#region Using Statements

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Storage;

#endregion


namespace GameStateManagement
{

    /// <summary>

    /// The credits screen is brought up over the top of the main menu

    /// screen, and provides the viewers a professional credit roll of all

    /// who worked on the game.

    /// </summary>

    class CreditsScreen : MenuScreen
   {

        #region Fields

        private Texture2D m_t2d_BackgroundTexture;

        private Vector2 m_v2_BackgroundPosition, m_v2_BackgroundOrigin;

        ContentManager content;

        private float m_f_Scroll;


        private int[] m_i_FontHeight = null;

        /// <summary>

        /// List of names to draw

        /// </summary>

        private string[] m_s_Names = null;


        // Create our menu entries.

        MenuEntry backMenuEntry = new MenuEntry("Back");

        String[] m_str_CreditEntries;

        public bool m_b_HasInputBeenTouched = false;

        #endregion


        #region Initialization

        /// <summary>

        /// Constructor.

        /// </summary>

        public CreditsScreen()

            : base("Credits Menu")

        {

            MenuEntries.Add(backMenuEntry);

            backMenuEntry.Selected += OnCancel;

        }

        #endregion


        #region Handle Input

        public override void LoadContent()
       {

            base.LoadContent();

            if (content == null)

                content = new ContentManager(ScreenManager.Game.Services, "Content");


            m_f_Scroll = ScreenManager.GraphicsDevice.Viewport.Height;

            m_t2d_BackgroundTexture = content.Load<Texture2D>("background");


            m_v2_BackgroundOrigin = new Vector2(m_t2d_BackgroundTexture.Width / 2, m_t2d_BackgroundTexture.Height / 2);

            m_v2_BackgroundPosition = new Vector2(m_t2d_BackgroundTexture.Width / 2, m_t2d_BackgroundTexture.Height / 2);


            m_str_CreditEntries = new String[126];

            //load names from file - names are stored line by line

            this.m_s_Names = File.ReadAllLines("Content/Names.txt");


            //create y coord for each name

            this.m_i_FontHeight = new int[m_s_Names.Length];

            int y = 0;//this.ScreenManager.GraphicsDevice.Viewport.Height / 2;


            for (int i = 0; i < this.m_i_FontHeight.Length; i++, y += this.ScreenManager.Font.LineSpacing)

                this.m_i_FontHeight[i] = y;

            SetMenuEntryText();

        }


        private void SetMenuEntryText()

        {

        }


        new private void OnCancel(object sender, PlayerIndexEventArgs e)

        {

            base.OnCancel(sender, e);

        }


        public override void Update(GameTime gameTime, bool otherScreenHasFocus,

                                                      bool coveredByOtherScreen)

        { 

            // Make the menu slide into place during transitions, using a

            // power curve to make things look more interesting (this makes

            // the movement slow down as it nears the end).

        float transitionOffset = (float)Math.Pow(TransitionPosition, 2);


            m_f_SpriteScale = ((transitionOffset - 1) * -1);

            m_f_SpriteScale *= 1000.0f;


            if (!m_b_HasInputBeenTouched)

                m_f_Scroll -= 175.0f * (float)gameTime.ElapsedGameTime.TotalSeconds;


            if (m_f_Scroll < -20096.25)

                base.OnCancel(PlayerIndex.One);

            base.Update(gameTime, otherScreenHasFocus, false);

        }


        public override void HandleInput(InputState input)

        {

            base.HandleInput(input);


            //if (input.RightStickCurrent.Y > 0)

            //{

                m_b_HasInputBeenTouched = true;

                m_f_Scroll -= 1.0f;

            //}


           /* if (input.RightStickCurrent.Y < 0)

            {

                m_b_HasInputBeenTouched = true;

                m_f_Scroll -= 10.0f;

            }*/

        }


        private float m_f_SpriteScale = 0.0f;

        private Color m_col_FontColor;

        public override void Draw(GameTime gameTime)

        {

            ScreenManager.SpriteBatch.Begin();

            ScreenManager.SpriteBatch.Draw(m_t2d_BackgroundTexture, new Rectangle(0, 0, (ScreenManager.GraphicsDevice.Viewport.Width * (int)m_f_SpriteScale) / 1000, (ScreenManager.GraphicsDevice.Viewport.Height * (int)m_f_SpriteScale) / 1000), Color.White);

            ScreenManager.SpriteBatch.End();

            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);

            //draw names

            this.ScreenManager.SpriteBatch.Begin();

            for (int i = 0; i < this.m_s_Names.Length; i++)

            {

                Vector2 pos = new Vector2((this.ScreenManager.GraphicsDevice.Viewport.Width / 2 -

                    (this.ScreenManager.Font.MeasureString(this.m_s_Names[i]).X / 2)), this.m_i_FontHeight[i] + m_f_Scroll);

                m_col_FontColor = Color.White;

                if (pos.Y < 100 || pos.Y > ScreenManager.GraphicsDevice.Viewport.Height - 100)

                    m_col_FontColor.A = 0;

                if (ScreenState == ScreenState.TransitionOn)

                    pos.X -= transitionOffset * 256;

                else

                    pos.X += transitionOffset * 512;

                this.ScreenManager.SpriteBatch.DrawString(this.ScreenManager.Font, this.m_s_Names[i], pos, m_col_FontColor);

            }

            this.ScreenManager.SpriteBatch.End();

            base.Draw(gameTime);

        }

        #endregion

    }

}


Introduction
     
The CreditsScreen class is part of a game project that utilizes the Microsoft XNA framework for game development. It serves as an overlay on top of the main menu screen and presents a professional-looking credit roll of all the people who worked on the game.


Fields and Initialization

#region Using Statements

// Import necessary namespaces

using System;

using System.IO;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Content;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Storage;

#endregion

The 'using' statements at the beginning of the class import the required namespaces for XNA game development.


class CreditsScreen : MenuScreen
{
    // Fields for textures, positions, and content
    private Texture2D m_t2d_BackgroundTexture;
    private Vector2 m_v2_BackgroundPosition, m_v2_BackgroundOrigin;
    ContentManager content;
    private float m_f_Scroll;

    // Arrays to store font heights and credit entries
    private int[] m_i_FontHeight = null;
    private string[] m_s_Names = null;

    // Menu entry for returning to the main menu
    MenuEntry backMenuEntry = new MenuEntry("Back");

    String[] m_str_CreditEntries;

    public bool m_b_HasInputBeenTouched = false;


     Here, we declare various fields for managing textures, positions, and content, as well as arrays to store font heights and credit entries. We also create a menu entry labeled "Back" to allow the player to return to the main menu.


Initialization

public CreditsScreen()
    : base("Credits Menu")
{
    MenuEntries.Add(backMenuEntry);
    backMenuEntry.Selected += OnCancel;
}

     The constructor initializes the CreditsScreen class by setting its name and adding the "Back" menu entry. Additionally, it hooks up an event handler for when the "Back" menu entry is selected.


LoadContent

public override void LoadContent()
{
    base.LoadContent();

    if (content == null)
        content = new ContentManager(ScreenManager.Game.Services, "Content");

    m_f_Scroll = ScreenManager.GraphicsDevice.Viewport.Height;

    // Load background texture
    m_t2d_BackgroundTexture = content.Load<Texture2D>("background");

    m_v2_BackgroundOrigin = new Vector2(m_t2d_BackgroundTexture.Width / 2, m_t2d_BackgroundTexture.Height / 2);
    m_v2_BackgroundPosition = new Vector2(m_t2d_BackgroundTexture.Width / 2, m_t2d_BackgroundTexture.Height / 2);

    m_str_CreditEntries = new String[126];

    // Load names from a file
    this.m_s_Names = File.ReadAllLines("Content/Names.txt");

    // Create Y coordinates for each name
    this.m_i_FontHeight = new int[m_s_Names.Length];

    int y = 0;

    for (int i = 0; i < this.m_i_FontHeight.Length; i++, y += this.ScreenManager.Font.LineSpacing)
        this.m_i_FontHeight[i] = y;

    SetMenuEntryText();
}

     In the 'LoadContent' method, we load the required content, such as the background texture and the list of names, from external files. We also set up Y coordinates for each name to control their position on the screen.


Handle Input 

public override void HandleInput(InputState input)
{
    base.HandleInput(input);

    m_b_HasInputBeenTouched = true;
    m_f_Scroll -= 1.0f;
}

     The 'HandleInput' method allows the player to interact with the credits screen. In this implementation, we scroll the credits by decreasing the 'm_f_Scroll' value when input is detected. You can customize this behavior according to your game's needs, such as allowing the player to scroll with different input methods.


Update & Draw
     The Update and Draw methods handle the animation and rendering of the credits roll. The key points are as follows:
  • The 'Update' method uses a power curve to make the movement look interesting, gradually slowing down as it nears the end of the credits.

  • The 'Draw' method renders the background and credit text. It adjusts the position and transparency of the text based on the current transition state.

     In conclusion, creating a credits screen for your game is an essential way to give credit to your development team and contributors. This CreditsScreen class provides a foundation for creating a professional-looking credits roll in your game. You can customize it further to fit the style and requirements of your game's menu system. Feel free to adapt and extend this code to create a unique credits screen for your game project. Happy coding!


Friday, July 1, 2022

79.) Character Armor Customization Part 3


       I played around with armor customization for my avatar and transformed myself into a COG soldier inspired by Gears of War. This is an in-game video of of it running inside the cyclone game engine. The menu background scene has been updated as well. This was just for fun and learning purposes.












Wednesday, November 2, 2016

43. How to Add Splash Screens to the Menu System


       The following tutorial is based on the Game State Management Sample and shows how to add splash screens as the startup of the game. This tutorial also works with the Network Game State Management Sample. I have posted my entire class below with comments that you can add to your screens folder. I named mine SplaceScreens.cs and make sure to change the namespace of this class to match your project. Also check out Robot Foot Games' tutorial on how to add multiple columns to the Game State Management Sample.


#region File Description
/*  ============================================
 *  SplashScreens.cs
 *  ============================================
 *
 * Upon the game's startup, Splash Screens are shown. The first screen shows the 
 * company logo and then it slowly fades away and displays the game engine logo. 
 * After the game engine logo fades away, the user is taken to the Title Screen.
 * 
 * 
*/
#endregion


#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace CycloneGameEngine
{
    class SplashScreens : GameScreen
  {
      #region Fields
      public enum GameType { Splash1, Splash2}
   
      GameType gametype = new GameType();
   
      #region Splash Screens

      #region Studio Logo
      Texture2D StudioLogo;
      float logoFade = 0;
      bool wasNorm = false;
      bool logoStarted = false;
      #endregion End of Studio Logo

      #region Engine Logo
      Texture2D EngineLogo;
      float logoFade2 = 0;
      bool wasNorm2 = false;
      bool logoStarted2 = false;
      #endregion End of Engine Logo

      #endregion End of Splash Screens

        ContentManager content;
   
        #endregion


        #region Initialization

        // Constructor.
        public SplashScreens()
        {
     
        }


        // Loads graphics content for this screen. The background texture is quite
        // big, so we use our own local ContentManager to load it. This allows us
        // to unload before going from the menus into the game itself, wheras if we
        // used the shared ContentManager provided by the Game class, the content
        // would remain loaded forever.
        //
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");

            StudioLogo = content.Load<Texture2D>("Images/Splash_Screens/logo2Main");
            EngineLogo = content.Load<Texture2D>("Images/Splash_Screens/Engine-Logo");
        }



        // Unloads graphics content for this screen.
        public override void UnloadContent()
        {
            content.Unload();
        }

        #endregion


        #region Update and Draw


        // Updates the background screen. Unlike most screens, this should not
        // transition off even if it has been covered by another screen: it is
        // supposed to be covered, after all! This overload forces the
        // coveredByOtherScreen parameter to false in order to stop the base
        // Update method wanting to transition off.
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            #region Update the 1st Splash Screen
            gametype = GameType.Splash1;

            // If we are at the splash screen
            if (gametype == GameType.Splash1)
            {

                if (!logoStarted)
                {
                    logoStarted = true;
                }

                // Fade the logo in , then out.
                if ((logoFade <= 245) && (wasNorm == false))
                    logoFade += (float)0.8;
                if (logoFade > 244)
                    wasNorm = true;
                if ((logoFade > 11) && (wasNorm == true))
                    logoFade -= 1;
                if ((logoFade < 11) && (wasNorm == true))
                {
                    gametype = GameType.Splash2;
                }
            }
            #endregion End of Drawing the 1st Splash Screen


            #region Update 2nd Splash Screen
            if (gametype == GameType.Splash2)
            {

                if (!logoStarted2)
                {
                    logoStarted2 = true;
                }

                // Fade the logo in , then out.
                if ((logoFade2 <= 245) && (wasNorm2 == false))
                    logoFade2 += (float)0.8;
                if (logoFade2 > 244)
                    wasNorm2 = true;
                if ((logoFade2 > 11) && (wasNorm2 == true))
                    logoFade2 -= 1;
                if ((logoFade2 < 11) && (wasNorm2 == true))
                {
                    ExitScreen();
                 
                }
            }
            #endregion End of Drawing the 2nd Splash Screen

            base.Update(gameTime, false, false);

        }


        // Draws the splash screens.
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
         
            #region Draw the 1st Splash Screen
            if (gametype == GameType.Splash1)
            {
                // Set the background color to black
                ScreenManager.GraphicsDevice.Clear(Color.Black);
                spriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive, SamplerState.PointWrap, DepthStencilState.Default, null);

                // Draw the logo to screen.              
                spriteBatch.Draw(StudioLogo, new Vector2(ScreenManager.GraphicsDevice.Viewport.Width / 2 - (StudioLogo.Width / 2), ScreenManager.GraphicsDevice.Viewport.Height / 2 - (StudioLogo.Height / 2)), new Color(255, 255, 255, (byte)logoFade));

                // End the spritebatch
                spriteBatch.End();
            }
            #endregion End of Drawing the 1st Splash Screen

            #region Draw the 2nd Splash Screen
            if (gametype == GameType.Splash2)
            {
                // Set the background color to black
                ScreenManager.GraphicsDevice.Clear(Color.Black);
                spriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive, SamplerState.PointWrap, DepthStencilState.Default, null);

                // Draw the logo to screen.              
                spriteBatch.Draw(EngineLogo, new Vector2(ScreenManager.GraphicsDevice.Viewport.Width / 2 - (EngineLogo.Width / 2), ScreenManager.GraphicsDevice.Viewport.Height / 2 - (EngineLogo.Height / 2)), new Color(255, 255, 255, (byte)logoFade2));

                // End the spritebatch
                spriteBatch.End();

            }
            #endregion End of Drawing the 2nd Splash Screen
        }
        #endregion
  }
}



Friday, June 3, 2016

39. Engine Update 5 Teaser


       This is a brief video teaser sneak peek of my next game engine update. Everything is still a work-in-progress. Since rigged and non-rigged models can be attached to the character now, I am working on character customization. Soon, players will be able to customize their armor. They will be able to swap out head-wear such as hats, helmets and mask. Soon they will also be able to swap between chest pieces and knee guards. This might not be fully shown in the next video update but I have this working for the most part. As players progress through the game, the upgrades to their suit will greatly improve their gameplay experience. Lately, I have been building up content for creating the models and assets that will go into the game world. I am improving artificial intelligence at the moment. This is just a teaser, so it will be a while before my next engine video update. I have been focusing on my 2D game and my independent studies to further educate myself and make far more progress. I am taking some time off and working on the gameplay! So excited. Below are some more screenshots of some fun I had with armor customization.







Sunday, November 3, 2013

12: Cyclone Game Engine Update 3



       Sorry for not posting videos for a while. This is not the latest progress video but an older one. This is a short video showing that I successfully created a working 2D/ 3D menu system with the help of the game state management's screen manager. I also got the menu system capable of displaying splash screens with transition effects upon the start-up of the game. The menu system also supports 3D models within it and description text when you hover over different menu items. I also got a sky-box functioning in the game. This video also shows the lens flare effect functioning and placed over the sun on the sky-box.  Its tricky when the program is drawing 2d and 3d together on the same screen under the 'Draw Method'.

       Thanks to Shawn Hargreaves who provided the most efficient way to go in his blog post, I was able to fix my skybox. When I was mixing 3D rendering with 2D objects using SpriteBatch, I may noticed that my 3D graphics no longer draw correctly after you have rendered sprites. All of the models triangles and polygons appeared to be disoriented and stretched leaving tons of gaps and holes. This is because the SpriteBatch changes several device renderstates. At this stage the actual game is still in Pre-Production Phase of development and I won't be revealing too much until the game is near completion. For now, I am improving the game engine and plan to post more progress footage of it. To see more progress, visit the Steel Cyclone Studio's Facebook Page. Below are some work-in-progress screenshots of 3D models I am creating.


Garage Interior WIP




Gun Model WIPs

       These are screenshots of a assault rifles I modeled which for now are just placeholders, not for an actual game. The M4A1 and M-16 are high-poly models which might have other attachments as later. The gun as well as the hands are arms in most of these screenshots were not rigged yet. I am still learning animation so the only in-game animations at the moment are programmed for when the gun shoots and turns slightly to indicate sprint. The arms in the screenshots below are simply a place-holder. Next I will be working on attaching the gun models to the animated character marine model shown in the video above. These gun model will most likely be used in starter kits I plan on putting together in the future. These models are all work-in-progress so they are not "perfect" by any means. 


M4A1


 ACR






Scar








M-16

The iron sight for instance is a bit too big, but the holographic sight is almost proportional. 







The iron sight needs to be a bit smaller. When you aim-down-sights, it would obscure the player's view at the moment, getting in the way. 







Wednesday, May 22, 2013

10: Cyclone Game Engine Menu System Update


       The following video above is a work-in-progress on the Cyclone Engine and does not represent final game footage. With the help of the Game State Management Sample, I was able to improve the menu system. Before the menu system was in the Game class and now each screen is a class of its own making the engine slightly more efficient and the menu more versatile. The menu system upon start up displays the Splash Screens which are the Studio Logo and the Cyclone Engine Logo. Then it takes you to the Title-Screen and the Main Menu following.  I am working on various transition effects as the user changes from one screen to another. I was able to get the menu system to display a credits video and I will be fleshing out the look and design of the menu system later. Other functioning screens are the Loading Screen and the Pause Menu Screen. 

       Networking functionality for online play is still in the works. The menu system displays an animated busy indicator whenever a network operation is in progress. In Multiplayer, once in the lobby, a list of players is displayed along with icons indicating who is currently talking and who has marked themselves as ready. When are gamers are ready, the menu loads the first map for now. Description text is displayed at the bottom as you scroll through menu items. I am currently improving the game's frame-rate on Xbox 360. The game currently runs at 30 frames per second on Xbox 360. I am still working on animations for the player and the gun. Soon, I will be adding the HUD since I was able to mix 2D and 3D. The Skybox displays better now in the game. Before, anyone could see the lines outlining the skybox. 


Game-State Management 


I updated my older menu system sample and added a 2D sprite-based scrolling fog effect. I am messing around with other effects for the menu system at the moment as well. 





Learning Level Design


       Understanding Level Design was one of my biggest challenges. I needed to place models and position them in such a way that would make the map dynamic and fun for the player to navigate. Level design was tough because objects in the game world needed a purpose; a reason as to why they exist and positioned in their location.









 The enemy spider beast model came from Psionic Games