Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
What is a Game Element?
#1
As the name suggests, a game element is a central part of the engine. With the help of a GameElement, various objects can be integrated into the game. To be more precise, the GameElement class is an abstract class that provides various functions and properties that are used by the engine.

Because the class is abstract, you can also create your own game elements. At the moment there are already a lot of game elements in the engine. For example a sprite, a static 3D element, a 3D model with animations and many more. These can either be displayed visually or, like the NavMesh for example, perform logical functions.

Let us take a closer look at the sprite game element for this tutorial.

Code:
using Genesis.Graphics;
using Genesis.Math;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Genesis.Core.GameElements
{
    /// <summary>
    /// Represents a sprite element in a 2D or 3D environment.
    /// </summary>
    public class Sprite : GameElement
    {
        /// <summary>
        /// Gets or sets the texture of the sprite.
        /// </summary>
        public Texture Texture { get; set; }

        /// <summary>
        /// Gets or sets the color of the sprite.
        /// </summary>
        public Color Color { get; set; } = Color.White;

        /// <summary>
        /// Gets or sets the texture coordinates of the sprite.
        /// </summary>
        public TexCoords TexCoords { get; set; } = new TexCoords();

        /// <summary>
        /// Gets or sets a value indicating whether occlusion culling is enabled for the sprite.
        /// </summary>
        public Boolean OcclusionCulling { get; set; }

        /// <summary>
        /// Initializes a new instance of the Sprite class with specified name, location, size, and texture.
        /// </summary>
        /// <param name="name">The name of the sprite.</param>
        /// <param name="location">The initial location of the sprite.</param>
        /// <param name="size">The size of the sprite.</param>
        /// <param name="texture">The texture for the sprite.</param>
        public Sprite(String name, Vec3 location, Vec3 size, Texture texture)
        {
            this.Name = name;
            this.Location= location;   
            this.Size= size;
            this.Texture= texture;
            this.OcclusionCulling = true;
        }

        /// <summary>
        /// Initializes the sprite element.
        /// </summary>
        /// <param name="game">The game instance.</param>
        /// <param name="renderDevice">The render device used for rendering.</param>
        public override void Init(Game game, IRenderDevice renderDevice)
        {
            base.Init(game, renderDevice);
            renderDevice.InitSprite(this);
            if(Texture != null)
            {
                if (Texture.RenderID == 0)
                {
                    renderDevice.LoadTexture(Texture);
                }
            }
        }

        /// <summary>
        /// Renders the sprite element.
        /// </summary>
        /// <param name="game">The game instance.</param>
        /// <param name="renderDevice">The render device used for rendering.</param>
        public override void OnRender(Game game, IRenderDevice renderDevice)
        {
            base.OnRender(game, renderDevice);

            if(game.SelectedScene.Camera.GetRect().Intersects(this.GetBounds2D()))
            {
                renderDevice.DrawSprite(this);
            }
        }

        /// <summary>
        /// Handles cleanup and resource disposal when the sprite is destroyed.
        /// </summary>
        /// <param name="game">The game instance.</param>
        public override void OnDestroy(Game game)
        {
            base.OnDestroy(game);
            game.RenderDevice.DisposeTexture(Texture);
        }

        /// <summary>
        /// Gets the 2D bounds of the sprite.
        /// </summary>
        /// <returns>A rectangular region representing the 2D bounds of the sprite.</returns>
        public Rect GetBounds2D()
        {
            return new Rect(Location.X, Location.Y, Size.X, Size.Y);
        }

        /// <summary>
        /// Gets the center location of the sprite.
        /// </summary>
        /// <returns>The center location of the sprite.</returns>
        public Vec3 GetCenterLocation()
        {
            return new Vec3(Location.X + (Size.X / 2), Location.Y + (Size.Y / 2));
        }

        /// <summary>
        /// Calculates the vertex coordinates of the sprite.
        /// </summary>
        /// <returns>An array containing the vertex coordinates of the sprite.</returns>
        public float[] CalculateVerticies()
        {
            float LeftX = this.Location.X - (Size.X / 2);
            float RightX = this.Location.X + (Size.X / 2);
            float top = this.Location.Y + (Size.Y / 2);
            float bottom = this.Location.Y - (Size.Y / 2);
           
            return new float[]
            {
                LeftX, bottom, 0.0f,
                LeftX, top, 0.0f,
                RightX, top, 0.0f,

                LeftX, bottom, 0.0f,
                RightX, top, 0.0f,
                RightX, bottom, 0.0f
            };
        }

    }
}

What is noticeable is that some sprite specific variables or properties have been created. There is also a constructor, which gives various variables an inherited and own property.

Code:
public Sprite(String name, Vec3 location, Vec3 size, Texture texture)
{
    this.Name = name;
    this.Location= location;   
    this.Size= size;
    this.Texture= texture;
    this.OcclusionCulling = true;
}

The next function we see is the Init function. As with the game behaviours, this function is called as soon as the element is created or the game is initialised. In this function we also pass the sprite to the RenderDevice to initialise it or to load it into the GPU memory. However, the standard renderers use so-called instantiated shapes, which would normally not make it necessary to initialise the sprite. The function is called for compatibility reasons.

The next step is to check if the texture already has a RenderID, i.e. if it does, it is already in the graphics card's memory. If not, it will be loaded from the renderer.

Code:
public override void Init(Game game, IRenderDevice renderDevice)
{
    base.Init(game, renderDevice);
    renderDevice.InitSprite(this);
    if(Texture != null)
    {
        if (Texture.RenderID == 0)
        {
            renderDevice.LoadTexture(Texture);
        }
    }
}

The OnRender function passes the sprite to the RenderDevice so that it can draw the sprite on the screen.

Code:
public override void OnRender(Game game, IRenderDevice renderDevice)
{
    base.OnRender(game, renderDevice);

    if(game.SelectedScene.Camera.GetRect().Intersects(this.GetBounds2D()))
    {
        renderDevice.DrawSprite(this);
    }
}

The last function we want to look at is the OnDestroy function. This is called when the game is finished, so that we can free up the memory in the graphics card that we have occupied with the sprite.

Code:
public override void OnDestroy(Game game)
{
    base.OnDestroy(game);
    game.RenderDevice.DisposeTexture(Texture);
}
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)