创建一个覆盖2D数组中所有绘制对象的矩形

时间:2014-05-03 19:17:20

标签: c# arrays xna xna-4.0 rectangles

我有一个在屏幕上同步移动的2D数组对象,我需要检测它们何时到达屏幕边缘以便它们改变方向(想想Space Invaders)。到目前为止,我已经使用预先定义为矩形的矩形来处理数组中对象的大小和位置,但是对象可以用导弹击中并且不再被绘制,因此当一侧的所有对象都被破坏时,矩形保持相同的大小,过早改变方向。

有没有更好的方法来做我想做的事情?这是我目前的功能代码:

(在LoadContent方法中)

invaderRect = new Rectangle(
    0, 0,
    invadersWide * (invaderImage.Width + 15) - 15,
    invadersHigh * (invaderImage.Height + 15) - 15);

(在更新方法中)

if ((invaderRect.X + invaderRect.Width) >= screenRectangle.Width - 15)
    invadersHitWall = true;
else if (invaderRect.X <= 15)
    invadersHitWall = false;

if (!invadersHitWall)
    invaderRect.X += 2;
else if (invadersHitWall)
    invaderRect.X -= 2;

1 个答案:

答案 0 :(得分:0)

这完全是组织代码的问题。您应该使用面向对象的方法。创建一个表示游戏对象的类。我将使用一个定义基本属性和方法的抽象基类。然后从该基类派生具体的游戏对象。具体的游戏对象&#39;构造函数的任务是初始化游戏对象。

public abstract class GameObject
{
    protected BlockType[,] _buildingBlocks; // The 2-d array. Replace "BlockType" 
                                            // by the type you are using.
    protected int _x0, _y0; // Indexes of the first non empty block.
    protected int _x1, _y1; // Indexes of the last  non empty block + 1.

    // Pixel coordinates of upper left corner of the intact game object.
    public Point Location { get; set; }

    // Represents the current position and size of the possibly diminished
    // game object in pixels.
    public Rectangle BoundingBox
    { 
        get {
            return new Rectangle(
                Location.X + BlockSize * _x0,
                Location.Y + BlockSize * _y0,
                BlockSize * (_x1 - _x0),
                BlockSize * (_y1 - _y0)
            );
        } 
    }

    public void Draw(Graphics g, int x, int x)
    {
        for (int i = _x0; i < _x1; i++) {
            for (int j = _y0; j < _y1; j++) {
                BlockType block = _buildingBlocks[i, j];
                if (block != null) {
                    // Replace by the appropriate drawing methods for XNA.
                    g.FillRectangle(block.Brush,
                                    x + BlockSize * i, y + BlockSize * j,
                                    BlockSize, BlockSize);
                }
            }
        }
    }

    // Call this after changes have been made to the arrray which may affect the
    // apparent size of the game object, e.g. after the object was hit by a bomb.
    protected void CalculateBounds()
    {
        _x0 = _buildingBlocks.GetLength(0);
        _y0 = _buildingBlocks.GetLength(1);
        _x1 = 0;
        _y1 = 0;
        for (int i = 0; i < _buildingBlocks.GetLength(0); i++) {
            for (int j = 0; j < _buildingBlocks.GetLength(1); j++) {
                if (buildingBlocks[i, j] != null) {
                   _x0 = Math.Min(_x0, i);
                   _y0 = Math.Min(_y0, j);
                   _x1 = Math.Max(_x1, i + 1);
                   _y1 = Math.Max(_y1, j + 1);
                }
            }
        }
    }

    public void DestroyBlocksAt(IEnumerable<Point> points)
    {
        //TODO: destroy hit blocks.

        CalculateBounds();
    }
}

对象被炸弹击中后,请调用CalculateBounds();以重新计算对象的实际大小。我们的想法是,不使用invaderRect,而是使用反映游戏对象真实范围的BoundingBox属性。 BoundingBox考虑了屏幕上游戏对象的位置(Location)和数组中的位置(_x0_x1_y0,{ {1}})。

这是原始草图。您可能需要对其进行优化并使其适应您当前的逻辑。不要使用像_y1这样的神奇数字。定义15之类的常量。这使得以后更容易更改数字并理解代码。

以下是入侵者类

的示例
public const int BlockSize = 15;

<强>更新

据我了解你的帖子,每个可移动的“东西”都存储在它自己的2D数组中,存储由它组成的15 x 15像素块。 public class Invader : GameObject { private const int WIDTH = 10, HEIGHT = 7; // Width and height of invader in blocks. public Invader() { _buildingBlocks = new BlockType[WIDTH, HEIGHT]; _x1 = WIDTH; _y1 = HEIGHT; _buildingBlocks[0, 0] = ... ... } } 是所有可见可移动事物的基类,如入侵者,太空飞船,炸弹等,并且是2D数组的包装(在我的代码示例中名为GameObject)。它增加了在被炸弹击中后确定物体真实界限所需的逻辑。 _buildingBlocks在2D阵列中炸弹后重新计算剩余物体的位置和大小(当然,每次物体形状发生变化时都必须调用它)。 CalculateBounds将这些内部2D数组边界(存储在BoundingBox_x0_x1_y0)移动到实际屏幕位置(存储在{{1}中通过乘以块大小(15个像素)并添加屏幕位置。

对于每种游戏对象类型(即可移动的形状类型),您必须派生一个类(例如,入侵者的类_y1)。然后为每个入侵者创建一个Location的入侵者对象。 Invader不是主要类。主要类包括游戏循环和游戏逻辑。它创建游戏对象并在它们四处移动时计算它们的新位置(存储在Invader invader = new Invader();属性中)。墙体击打逻辑现在可以与GameObject一起使用,而不是使用Location,它可以返回对象的实际大小和位置。

invaderRect