制作一个覆盖二维阵列中所有绘制对象的矩形
本文关键字:绘制 对象 阵列 一个 覆盖 二维 | 更新日期: 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
属性,而不是使用invaderRect
。BoundingBox
考虑游戏对象在屏幕上的位置(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;