C#游戏编程:保存或计算不变数据是否更好?

chu*_*ray 1 c# xna-4.0

我正在用C#XNA框架编写一个游戏,有些东西一直困扰着我.我永远不确定是否有利于程序保存数据(也就是说,将其存储在局部变量中)或每帧计算它.

虽然我已经决定连续计算改变每一帧的数据(比如播放器的位置,自动精灵的位置等等),但我不确定是否应该保存一些数据.窗口的宽度或每帧计算.我担心的是,计算一块数据,无论它有多小,每秒六十次都会产生相当多的开销,所以到目前为止我一直坚持节省大量资料.

这是我想要了解的一个例子:

//  Scenario 1: Save the data

//  This class represents an entry within a menu.
public class MenuEntry
{
    //  The constructor takes a SpriteFont variable to calculate the size of 
    //  the given string (which is the text used to represent this entry in a 
    //  menu) and save that data for later access
    public MenuEntry(string entryText, SpriteFont font)
    {
        this.entryText = entryText;

        //  Initializes a local value of the font to lessen the burden of method calls.
        SpriteFont font = menuScreen.GameInstance.MenuFont;

        //  Initialize the bounding rectangle for this 'MenuEntry' object.
        entryRectangle = new Rectangle();

        //  Based on the text given, adjust the values of the rectangle.
        entryRectangle.Height = font.LineSpacing;
        entryRectangle.Width = (int)font.MeasureString(entryText).X;
    }

    //  Object methods

    //  This method simply sets the location of the 'hitbox' of this MenuEntry based
    //  on the given position.
    public void SetLocation(int x, int y)
    {
        entryRectangle.X = x;
        entryRectangle.Y = y;
    }

    //  Object fields

    //  Rectangle that represents the 'hitbox' for this MenuEntry.  In other
    //  words, the place on the screen over which the mouse can hover to cause
    //  this MenuEntry to be the selected item on the menu
    private Rectangle entryRectangle;

    //  The 'entryText' is the string representation of this MenuEntry object in
    //  a menu.
    private string entryText;
}

//  Scenario 2: Calculate per frame

//  This class also represents an entry within a menu.
public class MenuEntry
{
    //  The constructor simply initializes the value of the text field
    public MenuEntry(string entryText)
    {
        this.entryText = entryText;
    }

    //  Object methods

    //  Instead of saving the data, these methods allow this MenuEntry
    //  to calculate its 'hitbox' whenever this method is called, 
    //  returning the width and height variables associated with the
    //  text representation of this MenuEntry object.
    public virtual int GetWidth(SpriteFont font)
    {
        return (int)font.MeasureString(Text).X;
    }

    public virtual int GetHeight(SpriteFont font)
    {
        return font.LineSpacing;
    }

    //  Object fields

    //  The MenuEntry still must know where it's located, but this component
    //  is less memory intensive than a 'Rectangle' object (correct me if
    //  I'm wrong on this one)
    private Vector2 position;

    //  This property allows for the controlling menu to place and replace the
    //  MenuEntry, though this value must be calculated each frame even though
    //  the position may be the same for each frame.
    public Vector2 Position
    {
        get { return position; }
        set { position = value; }
    }

    //  The 'entryText' is the string representation of this MenuEntry object in
    //  a menu.
    private string entryText;
}

//  Example in menu:

public class Menu
{
    //  For the sake of simplicity, the constructor simply receives a list of entries
    //  and initializes them to a local variable.  If we're using Scenario 1, the  
    //  positions for each rectangle must be set.
    public class Menu(SpriteFont menuFont, List<MenuEntry> menuEntries)
    {
        this.menuFont = menuFont;
        this.menuEntries = menuEntries;

        #if Scenario 1

        Vector2 position = new Vector2(0f, 175f);

        for(int i = 0; i < menuEntries.Count; i++)
        {
            //  Initialize a local reference to the current MenuEntry.
            MenuEntry menuEntry = menuEntries[i];

            //  Adjust this entry toward the center of the screen.  Assume it
            //  has access to a static viewport variable.
            position.X = Game.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;

            //  Set the entry's position to the calculated position.  There must be
            //  casts as these are floating-point values.
            menuEntry.SetLocation((int)position.X, (int)position.Y);

            //  Move down for the next entry the size of this entry
            position.Y += menuEntry.GetHeight(this);
        }

        #endif
    }

    //  This method is called by the main update method once per frame.
    public void Update(GameTime gameTime)
    {
        #if Scenario 1

        //  Nothing, as the MenuEntry items don't need to move and their positions
        //  have already been set.

        #elif Scenario 2

        Vector2 position = new Vector2(0f, 175f);

        for(int i = 0; i < menuEntries.Count; i++)
        {
            //  Initialize a local reference to the current MenuEntry.
            MenuEntry menuEntry = menuEntries[i];

            //  Adjust this entry toward the center of the screen.  Assume it
            //  has access to a static viewport variable.
            position.X = Game.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;

            //  Set the entry's position
            menuEntry.Position = position;

            //  Move down for the next entry the size of this entry
            position.Y += menuEntry.GetHeight(this);
        }

        #endif
    }

    //  Object fields

    //  The list of MenuEntry items associated with this Menu.
    private List<MenuEntry> menuEntries;

    //  The font used for this Menu.
    private SpriteFont menuFont;
}
Run Code Online (Sandbox Code Playgroud)

虽然这个例子有点长,但我觉得它充分地封装了我的问题.那么,将更多数据保存到对象(在示例中,保存矩形结构)或者每帧计算这些数据更好吗?请注意,我所说的数据在帧之间不会改变.

Cod*_*aos 6

每秒60次,无需简单计算.您的计算机每秒可以进行数百万次简单计算.

选择一个产生易于维护代码的产品.由于窗口可以调整大小,我强烈建议在每个帧上重新计算基于窗口的内容,如宽高比,投影矩阵等.

此类性能问题仅与经常执行的代码相关.每秒说> 100万次.

对于罕见的执行,只有昂贵的调用,如IO很重要.

所以我对这个问题有所了解:配置文件找到瓶颈,然后优化它.对于所有其他代码,请使用最清晰的最简单版本.