我有一个在屏幕上同步移动的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;
答案 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