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!


No comments:

Post a Comment