制作一个覆盖二维阵列中所有绘制对象的矩形

本文关键字:绘制 对象 阵列 一个 覆盖 二维 | 更新日期: 2023-09-27 18:01:25

我有一个在屏幕上同步移动的2D对象阵列,我需要检测它们何时击中屏幕边缘,以便改变方向(想想太空入侵者(。到目前为止,我已经使用了一个矩形,该矩形预定义为阵列中对象的大小和位置,但对象可以被导弹击中,并且不再被绘制,因此当一侧的所有对象都被摧毁时,矩形保持不变,并且它们过早地改变方向。

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

(加载内容法(

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;

制作一个覆盖二维阵列中所有绘制对象的矩形

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

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();以重新计算物体的实际大小。其想法是,您将使用反映游戏对象真实范围的BoundingBox属性,而不是使用invaderRectBoundingBox考虑游戏对象在屏幕上的位置(Location(和阵列内的位置(_x0_x1_y0_y1(。

这是一幅草图。您可能需要完善它,并使其适应您当前的逻辑。不要使用像15这样的神奇数字。定义像public const int BlockSize = 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阵列中,存储着它所组成的15 x 15像素块。GameObject是所有可见可移动物体的基类,如入侵者、太空船、炸弹等,是2D阵列的包装器(在我的代码示例中称为_buildingBlocks(。它增加了确定物体被炸弹击中后的真实边界所需的逻辑。CalculateBounds在2D阵列中重新计算炸弹击中后剩余物体的位置和大小(当然,每次物体形状发生变化时都必须调用它(。BoundingBox通过乘以块大小(15个像素(并加上屏幕位置,将这些内部2D阵列边界(存储在_x0_x1_y0_y1中(移动到实际屏幕位置(存储在Location属性中(。

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

Rectangle invaderBounds = invader.BoundingBox;
bool isLeftWallHit = invaderBounds.Left <= 0;
bool isRightWallHit = invaderBounds.Right >= screenRectangle.Width;
bool isUpperWallHit = invaderBounds.Top <= 0;
bool isLowerWallHit = invaderBounds.Bottom >= screenRectangle.Height;