在本章,你将学会:
1、充分利用面向对象编程的观点来对多个精灵进行控制
2、准备编写易于理解和组织良好的游戏循环逻辑
3、根据游戏逻辑的需要动态创建对象
4、对适用于矢量图形的变换操作进行控制
5、了解基本的冲突检测算法
第一项改造任务
到目前为止,我们在屏幕上显示出了一些光栅精灵,并创建了一个带有动画效果的简单2D场景。我们也利用了一些GPU加速的功能并使用2D向量来进行位置定义并进行移动操作。但是,游戏需要许多的以不同速度、方向进行移动的精灵。我们怎样绘制多个相对独立但又同时存在的精灵,并对复杂的游戏循环进行管理呢?
我们可以通过把一个好的面向对象设计和基于矢量图形的XAML的强大能力结合到一起来解决上面的问题。
创建基于XAML的矢量图形精灵
首先,我们将把所有的基于矢量图形的XAML转换为用户控件。然后我们将创建许多使用了继承的面向对象的类,它具有非常强大的简化代码重用的能力。在这个例子中,我们不打算使用XAML来进行精灵实例的创建,我们将使用C#代码来实例化它们:
1、创建一个新的基于C#的Silverlight应用程序项目,项目的名称为SilverlightInvaders2DVector。
2、对配置文件进行必要的修改以便启用GPU加速。我们在前一章节已经学习过该步骤。
3、找到本游戏需要的保存了可缩放矢量图形的XAML格式文件。
4、为每一个矢量图形(XAML文件)进行如下的操作步骤(5至15)。
5、根据下面表格的内容新建对应的用户控件:
XAML文件名 |
用户控件名 |
ALIEN_01_01.XAML |
BlueAlien |
ALIEN_02_01.XAML |
RedAlien |
ALIEN_03_01.XAML |
GreenAlien |
SHIP_01_01.XAML |
Ship |
TENT_01_01.XAML |
Tent |
打开新建的用户控件的XAML代码,像前一章的操作步骤一样创建Ghost用户控件。
6、现在,在主Canvas的定义中使用 Background="White" 对 Background="{x:Null}" 进行替换。然后添加相应的Width和Height值以便更改Canvas的大小。白色的背景有助于你顺利地找到每一个卡通造型的精确属性值。
7、一旦你找到了正确的Width和Height属性值后,再用 Background="{x:Null}" 把 Background="White" 替换回来。因为我们并不想在此呈现出一个白色的矩形背景。
8、在主Canvas的定义中添加下面的代码:
RenderTransformOrigin="0.5,0.5"
9、完整的代码和下面类似:
<
Canvas
x:Name
="LayoutRoot"
Background
="
{x:Null}
"
Width
="195"
Height
="128"
RenderTransformOrigin
="0.5,0.5"
>
10、在Expression Blend中打开该XAML代码。
11、点击“在对象和时间线”下面的名称为“LayoutRoot”的主Canvas,然后找到它的“属性”选项卡。
12、展开“转换”属性并点击“中心点”选项卡,然后在X和Y文本框中输入0.5.如下图所示:
13、选择“缩放”选项卡,点击“使用相对值”并在X和Y文本框中输入0.5。
14、回到XAML代码中,你将看到“Canvas.RenderTransform”和“TransformGroup”的代码。这是Expression Blend创建的。为RotateTransform指定其名称为“rotateSprite”,如下面的代码所示:
<RotateTransform x:Name="rotateSprite" Angle="0"/>
15、对每个用户控件重复相同的操作,下面是GreenAlien的效果图:
创建一个特定的精灵管理类
在创建了各个用户控件后,我们需要根据这些用户控件来对许多的精灵进行移动操作。现在,我们要创建一个超类来对大多数和用户控件作为精灵运行有关的公共操作进行管理。
1、继续SilverlightInvaders2DVector项目
2、新建一个新的抽象类:UpdateableUIElement
3、添加如下的public属性定义:
public bool isAlive { set; get; }
4、添加如下的public抽象方法:
public abstract void Update(TimeSpan elapsedTime);
5、创建一个新的抽象类:SpriteWrapper(继承自UpdateableUIElement类):
public abstract class SpriteWrapper: UpdateableUIElement
6、增加如下的protected成员
//
Indicates whether the sprite has been rendered or not
protected
bool
_rendered
=
false
;
//
The UserControl instance associated to this SpriteWrapper
protected
UserControl _ucSpriteUC;
//
The parent Canvas
protected
Canvas _cnvParent;
7、增加如下的protected成员和相应的public属性
//
The location
protected
Point _location;
public
Point location
{
set
{ _location
=
value; }
get
{
return
_location; }
}
//
The speed
protected
Point _speed;
public
Point speed
{
set
{ _speed
=
value; }
get
{
return
_speed; }
}
//
The rendered size
protected
Size _size;
public
Size size
{
get
{
if
(
!
_rendered)
return
new
Size();
else
return
_size;
}
}
8、增加如下的public抽象方法(使用了工厂方法设计模式):
public abstract UserControl CreateSpriteUC();
9、增加如下带有两个参数的构造器:
SpriteWrapper构造器
public
SpriteWrapper(Canvas cnvParent, Point initialLocation)
{
_cnvParent
=
cnvParent;
_ucSpriteUC
=
CreateSpriteUC();
_location
=
initialLocation;
//
Initially, the sprite is static
_speed
=
new
Point(
0
,
0
);
cnvParent.Children.Add(_ucSpriteUC);
//
Set the initial position for the sprite
_ucSpriteUC.SetValue(Canvas.LeftProperty, _location.X);
_ucSpriteUC.SetValue(Canvas.TopProperty, _location.Y);
//
By default, it is alive
isAlive
=
true
;
}
10、增加如下的public方法,此方法根据精灵的原位置、速度和经过的时间来计算精灵当前的位置:
CalculateNewPosition方法
public
void
CalculateNewPosition(TimeSpan elapsedTime)
{
//
Update the X-coordinate according to the elapsed time and the speed
_location.X
+=
_speed.X
*
(
double
)elapsedTime.TotalSeconds;
//
Update the Y-coordinate according to the elapsed time and the speed
_location.Y
+=
_speed.Y
*
(
double
)elapsedTime.TotalSeconds;
}
11、增加如下的public方法:
CalculateSize方法
public
virtual
void
CalculateSize()
{
_size
=
new
Size((
double
)_ucSpriteUC.GetValue(
Canvas.ActualWidthProperty)
*
0.5
,
(
double
)_ucSpriteUC.GetValue(
Canvas.ActualHeightProperty)
*
0.5
);
}
12、增加如下的public方法:
public
void
InvertXDirection()
{
_speed.X
*=
-
1
;
}
public
void
InvertYDirection()
{
_speed.Y
*=
-
1
;
}
13、重写(override)Update方法:
Update方法
public
override
void
Update(TimeSpan elapsedTime)
{
if
(
!
isAlive)
return
;
if
(
!
_rendered)
{
//
First time rendered, save the actual size
CalculateSize();
//
Flag the sprite as rendered
_rendered
=
true
;
}
CalculateNewPosition(elapsedTime);
//
Set the new location for the sprite
_ucSpriteUC.SetValue(Canvas.LeftProperty, _location.X);
_ucSpriteUC.SetValue(Canvas.TopProperty, _location.Y);
}
对用户控件进行封装
可能会问到的一个问题是:为什么使用了一个用户控件来对精灵进行封装而不是创建一个接口呢?答案就是要简单化,在保证简单的同时利用可视化开发工具的优点。
每一个用户控件都有XAML代码和C#代码。但是,假如我们花点时间看看由IDE自动生成的C#代码(.xaml.cs文件)后,我们将看到一个public partial class的定义,如下面的类似:
public partial class BlueAlien : UserControl
我们不能为这个用户控件的子类添加一个接口或者更改其父类,因为另一部分代码存放于一个我们不能进行修改的文件中(.xaml.g.cs文件)。出于这个原因,我们不能添加接口或者改变它的子类(我仔细想想还是没弄明白,不能修改父类倒也罢了,怎么就不能添加一个接口呢?)。
因此最简单的对定义在用户控件中的精灵进行管理的方式是使用一个类来进行包装,我们也正是这样做的。
备注:我们也能使用其它方式来实现相同的目标。例如,我们可以创建一个继承自Control类(System.Windows.Controls)的自定义控件,然后我们可以创建一个控件模板(ControlTemplate)来定义它的外观。
为卡通人物创建一个超类
现在我们准备为游戏中的每一个卡通造型创建继承自SpriteWrapper的特定子类。因为我们的游戏中有三种不同类型的外星人,因此我们将创建一个AlienWrapper类来对这些外星人的公共行为进行封装。
1、继续SilverlightInvaders2DVector项目
2、创建一个新的继承自SpriteWrapper的抽象类:AlienWrapper:
public abstract class AlienWrapper : SpriteWrapper
3、添加如下的protected变量(外星人必须以特定的速度旋转):
//
The current rotation angle
protected
double
_angle;
//
The rotation speed
protected
double
_rotationSpeed;
4、添加如下属性:
public
double
rotationSpeed
{
set
{ _rotationSpeed
=
value; }
get
{
return
_rotationSpeed; }
}
5、添加如下的构造器方法:
AlienWrapper构造器
public
AlienWrapper(Canvas cnvParent, Point initialLocation)
:
base
(cnvParent, initialLocation)
{
//
Add any necessary additional instructions
//
The default speed for X = 50
_speed
=
new
Point(
50
,
0
);
//
The default rotation speed = 0
_rotationSpeed
=
0
;
_angle
=
0
;
}
6、添加如下用来计算精灵旋转角度的public方法:
CalculateNewAngle方法
public
void
CalculateNewAngle(TimeSpan elapsedTime)
{
//
Update the angle according to the elapsed time and the speed
if
(_rendered)
_angle
=
((_angle
+
_rotationSpeed
*
(
double
)elapsedTime.TotalSeconds)
%
360
);
}
7、添加如下的public方法
public
void
InvertRotationSpeed()
{
_rotationSpeed
*=
-
1
;
}
为每个卡通造型创建其对应的子类
现在我们将为每一个卡通造型创建其特定的子类。它们中的一些是SpriteWrapper的子类,而其它则是AlienWrapper的子类。对于创建所有AlienWrapper子类的步骤都是非常相似的。但是,我们将在稍后讨论怎样对代码进行重构。
1、继续SilverlightInvaders2DVector项目
2、创建一个新的名称为BlueAlienWrapper的继承自AlienWrapper的子类,代码如下:
public class BlueAlienWrapper : AlienWrapper
3、添加如下的构造器代码:
public
BlueAlienWrapper(Canvas cnvParent, Point initialLocation)
:
base
(cnvParent, initialLocation)
{
//
Add any necessary additional instructions
rotationSpeed
=
5
;
}
4、重写(Override)CreateSpriteUC方法,代码如下:
public
override
UserControl CreateSpriteUC()
{
return
new
BlueAlien();
}
5、重写(Override)Update方法,代码如下:
public
override
void
Update(TimeSpan elapsedTime)
{
base
.Update(elapsedTime);
CalculateNewAngle(elapsedTime);
(_ucSpriteUC
as
BlueAlien).rotateSprite.Angle
=
_angle;
}
6、创建一个新的名称为RedAlienWrapper的继承自AlienWrapper的子类,代码如下:
public class RedAlienWrapper : AlienWrapper
7、添加如下的构造器代码:
public
RedAlienWrapper(Canvas cnvParent, Point initialLocation)
:
base
(cnvParent, initialLocation)
{
//
Add any necessary additional instructions
rotationSpeed
=
15
;
}
8、重写(Override)CreateSpriteUC方法,代码如下:
public
override
UserControl CreateSpriteUC()
{
return
new
RedAlien();
}
9、重写(Override)Update方法,代码如下:
public
override
void
Update(TimeSpan elapsedTime)
{
base
.Update(elapsedTime);
CalculateNewAngle(elapsedTime);
(_ucSpriteUC
as
RedAlien).rotateSprite.Angle
=
_angle;
}
10、创建一个新的名称为GreenAlienWrapper的继承自AlienWrapper的子类,代码如下:
public class GreenAlienWrapper : AlienWrapper
11、添加如下的构造器代码:
public
GreenAlienWrapper(Canvas cnvParent, Point initialLocation)
:
base
(cnvParent, initialLocation)
{
//
Add any necessary additional instructions
rotationSpeed
=
25
;
}
12、重写(Override)CreateSpriteUC方法,代码如下:
public
override
UserControl CreateSpriteUC()
{
return
new
GreenAlien();
}
13、重写(Override)Update方法,代码如下:
public
override
void
Update(TimeSpan elapsedTime)
{
base
.Update(elapsedTime);
CalculateNewAngle(elapsedTime);
(_ucSpriteUC
as
GreenAlien).rotateSprite.Angle
=
_angle;
}
14、创建一个新的名称为ShipWrapper的继承自SpriteWrapper的子类,代码如下:
public class ShipWrapper : SpriteWrapper
15、添加如下的protected成员:
//
Speed to move in the X axis
protected
double
_incrementX
=
50
;
//
Speed to move in the Y axis
protected
double
_incrementY
=
50
;
16、添加如下的构造器代码:
public
ShipWrapper(Canvas cnvParent, Point initialLocation)
:
base
(cnvParent, initialLocation)
{
//
Add any necessary additional instructions
}
17、重写(Override)CreateSpriteUC方法,代码如下:
public
override
UserControl CreateSpriteUC()
{
return
new
Ship();
}
18、添加如下的public方法,这些方法用来简化对精灵进行移动的控制过程。
public
void
GoUp()
{
_speed.Y
=
-
_incrementY;
_speed.X
=
0
;
}
public
void
GoDown()
{
_speed.Y
=
_incrementY;
_speed.X
=
0
;
}
public
void
GoLeft()
{
_speed.X
=
-
_incrementX;
_speed.Y
=
0
;
}
public
void
GoRight()
{
_speed.X
=
_incrementX;
_speed.Y
=
0
;
}
19、创建一个新的名称为TentWrapper的继承自SpriteWrapper的子类,代码如下:
public class TentWrapper : SpriteWrapper
20、添加如下的构造器代码:
public
TentWrapper(Canvas cnvParent, Point initialLocation)
:
base
(cnvParent, initialLocation)
{
//
Add any necessary additional instructions
}
21、重写(Override)CreateSpriteUC方法,代码如下:
public
override
UserControl CreateSpriteUC()
{
return
new
Tent();
}
为支持游戏循环创建相应的方法
首先,我们将在MainPage类中创建许多方法,这些方法用来创建精灵、绘制动画和控制这些精灵的行为。然后我们将编写一个复杂的游戏循环代码:
1、继续SilverlightInvaders2DVector项目
2、打开MainPage.xaml.cs文件并在类中添加如下的private成员:
//
The aliens
private
List
<
AlienWrapper
>
_aliens;
//
The total number of tents
private
int
_totalTents
=
4
;
//
The total number of rows and cols for the aliens
private
int
_totalRows
=
5
;
private
int
_totalCols
=
11
;
//
The four tents
private
List
<
TentWrapper
>
_tents;
//
The ship
private
ShipWrapper _ship;
//
The aliens' row height
private
double
_rowHeight
=
75
;
//
The aliens' col width
private
double
_colWidth
=
75
;
//
Holds the time when the method finished rendering a frame
private
DateTime _LastTick;
//
The upper left corner for the animation
private
Point _upperLeftCorner
=
new
Point(
0
,
0
);
//
The bottom right corner for the animation
private
Point _bottomRightCorner
=
new
Point(
0
,
0
);
//
The last bound touched was the right bound
private
bool
_lastTouchRight
=
false
;
3、添加如下的方法代码:
CreateAliens方法
private
void
CreateAliens()
{
//
Create the list of aliens
_aliens
=
new
List
<
AlienWrapper
>
(_totalRows
*
_totalCols);
AlienWrapper alien;
Point position;
for
(
int
col
=
0
; col
<=
_totalCols; col
++
)
{
for
(
int
row
=
0
; row
<
_totalRows; row
++
)
{
position
=
new
Point((col
*
_colWidth), (row
*
_rowHeight));
switch
(row)
{
case
0
:
alien
=
new
GreenAlienWrapper(LayoutRoot,
position);
break
;
case
1
:
alien
=
new
BlueAlienWrapper(LayoutRoot,
position);
break
;
case
2
:
alien
=
new
BlueAlienWrapper(LayoutRoot,
position);
break
;
case
3
:
alien
=
new
RedAlienWrapper(LayoutRoot,
position);
break
;
case
4
:
alien
=
new
RedAlienWrapper(LayoutRoot,
position);
break
;
default
:
alien
=
new
RedAlienWrapper(LayoutRoot,
position);
break
;
}
_aliens.Add(alien);
}
}
}
4、添加如下的方法代码:
private
void
CreateTents()
{
_tents
=
new
List
<
TentWrapper
>
(_totalTents);
for
(
int
i
=
0
; i
<
_totalTents; i
++
)
{
_tents.Add(
new
TentWrapper(LayoutRoot,
new
Point(
250
*
i,
600
)));
}
}
5、添加如下的方法代码:
private
void
CreateShip()
{
//
Create the ship
_ship
=
new
ShipWrapper(LayoutRoot,
new
Point(
500
,
800
));
}
6、添加如下的方法代码:
GoDownOneRow方法
private
void
GoDownOneRow()
{
//
Bound reached, invert direction
for
(
int
i
=
0
; i
<
_aliens.Count; i
++
)
{
if
(_aliens[i].isAlive)
{
_aliens[i].InvertXDirection();
_aliens[i].InvertRotationSpeed();
//
Advance one row
_aliens[i].location
=
new
Point(_aliens[i].location.X,
_aliens[i].location.Y
+
_rowHeight);
}
}
}
7、添加如下用来进行边界检测的代码:
private
void
GoDownOneRow()
{
//
Bound reached, invert direction
for
(
int
i
=
0
; i
<
_aliens.Count; i
++
)
{
if
(_aliens[i].isAlive)
{
_aliens[i].InvertXDirection();
_aliens[i].InvertRotationSpeed();
//
Advance one row
_aliens[i].location
=
new
Point(_aliens[i].location.X,
_aliens[i].location.Y
+
_rowHeight);
}
}
}
private
void
CheckLeftBound()
{
//
If any alien touches the left bound, go down and invert direction
for
(
int
i
=
0
; i
<
_aliens.Count; i
++
)
{
if
(_aliens[i].isAlive)
{
if
(_aliens[i].location.X
<
(_upperLeftCorner.X
+
1
))
{
//
Left bound reached
GoDownOneRow();
_lastTouchRight
=
false
;
break
;
}
}
}
}
private
void
CheckRightBound()
{
//
If any alien touches the right bound, go down and invert direction
for
(
int
i
=
0
; i
<
_aliens.Count; i
++
)
{
if
(_aliens[i].isAlive)
{
if
(_aliens[i].location.X
>
(_bottomRightCorner.X
-
_colWidth))
{
//
Right bound reached
GoDownOneRow();
_lastTouchRight
=
true
;
break
;
}
}
}
}
private
void
CheckBounds()
{
if
(_lastTouchRight)
CheckLeftBound();
else
CheckRightBound();
}
编写游戏循环代码
是该为主游戏循环编写代码的时候了。我们必须显示出上面的卡通造型并移动它们,然后根据玩家按下的键码来对飞船的移动进行控制:
1、继续SilverlightInvaders2DVector项目
2、打开MainPage.xaml的主XAML代码并使用下面的代码替换现有代码:
<
UserControl
x:Class
="SilverlightInvaders2DVector.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/
presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
Width
="1366"
Height
="768"
xmlns:SilverlightInvaders2D
=
"clr-namespace:SilverlightInvaders2DVector"
>
<
Canvas
x:Name
="LayoutRoot"
Background
="White"
>
<!--
A button to start the game loop
-->
<
Button
x:Name
="btnStartGame"
Content
="Start the game!"
Canvas.Left
="200"
Canvas.Top
="20"
Width
="200"
Height
="30"
Click
="btnStartGame_Click"
>
</
Button
>
</
Canvas
>
</
UserControl
>
3、打开MainPage.xaml.cs文件
4、现在,添加如下代码,该事件处理程序代码将输出每一帧并通过调用先前编写好的方法来对必要的SpriteWrapper实例进行更新:
RenderFrame事件处理程序
private
void
RenderFrame(
object
sender, EventArgs e)
{
//
Hold the elapsed time after the last call to this method
TimeSpan elapsedTime
=
(DateTime.Now
-
_LastTick);
for
(
int
iTent
=
0
; iTent
<
_totalTents; iTent
++
)
{
_tents[iTent].Update(elapsedTime);
}
for
(
int
iAlien
=
0
; iAlien
<
_aliens.Count(); iAlien
++
)
{
_aliens[iAlien].Update(elapsedTime);
}
_ship.Update(elapsedTime);
CheckBounds();
//
Save the current time
_LastTick
=
DateTime.Now;
}
5、添加如下的代码,该事件处理程序将对按下的键进行检测然后对飞船进行移动:
Page_KeyDown事件处理程序
private
void
Page_KeyDown(
object
sender, KeyEventArgs e)
{
switch
(e.Key)
{
case
Key.Left:
_ship.GoLeft();
break
;
case
Key.Right:
_ship.GoRight();
break
;
case
Key.Up:
_ship.GoUp();
break
;
case
Key.Down:
_ship.GoDown();
break
;
}
}
6、最后,添加如下的代码,该事件处理程序将对button的Click事件进行处理(这些代码将创建所有的精灵并开始游戏):
btnStartGame_Click事件处理程序
private
void
btnStartGame_Click(
object
sender, RoutedEventArgs e)
{
//
Hide the button
btnStartGame.Visibility
=
Visibility.Collapsed;
CreateAliens();
CreateTents();
CreateShip();
//
Define the upper left corner and bottom right corner for the animations
_upperLeftCorner
=
new
Point(_aliens[
0
].location.X,
_aliens[
0
].location.Y);
_bottomRightCorner
=
new
Point(LayoutRoot.ActualWidth
-
_colWidth, LayoutRoot.ActualHeight
-
_rowHeight)
;
//
Save the current time
_LastTick
=
DateTime.Now;
//
Add an EventHandler to render each frame
CompositionTarget.Rendering
+=
RenderFrame;
//
Add an EventHandler to check for each key down
this
.KeyDown
+=
new
KeyEventHandler(Page_KeyDown);
}
7、编译并运行本解决方案,效果图如下:
冲突检测
当外星人和飞船接触后我们希望这些外星人显示出不同的颜色,为此我们将进行如下步骤:
1、继续SilverlightInvaders2DVector项目
2、打开SpriteWrapper类代码:
3、添加如下的public方法,该方法返回一个表示指定精灵边界的矩形:
public
Rect UCBounds()
{
return
new
Rect(_location, _size);
}
4、添加如下的public方法来对指定的精灵进行冲突检测:
public
bool
CollidesWith(SpriteWrapper spriteToCheck)
{
Rect rect1
=
UCBounds();
Rect rect2
=
spriteToCheck.UCBounds();
rect1.Intersect(rect2);
return
(rect1
!=
Rect.Empty);
}
5、添加如下用来对精灵进行绘制的public方法:
PaintGradient方法
public
void
PaintGradient(Color newColor1, Color newColor2)
{
LinearGradientBrush linearGradientBrush
=
new
LinearGradientBrush();
GradientStop gradientStop1
=
new
GradientStop();
gradientStop1.Color
=
newColor1;
gradientStop1.Offset
=
0
;
GradientStop gradientStop2
=
new
GradientStop();
gradientStop2.Color
=
newColor2;
gradientStop2.Offset
=
1.0
;
linearGradientBrush.StartPoint
=
new
Point(
0
,
0
);
linearGradientBrush.EndPoint
=
new
Point(
1
,
1
);
linearGradientBrush.GradientStops.Add(gradientStop1);
linearGradientBrush.GradientStops.Add(gradientStop2);
//
Obtain the main Canvas by its name
//
All the User Controls associated to a SpriteWrapper
//
must use the name LayoutRoot for the main Canvas
Canvas canvas
=
(_ucSpriteUC.FindName(
"
LayoutRoot
"
)
as
Canvas);
for
(
int
i
=
0
; i
<
canvas.Children.Count; i
++
)
{
if
(canvas.Children[i]
is
Path)
{
Path path
=
(canvas.Children[i]
as
Path);
//
Fill each path with the linear gradient brush
path.Fill
=
linearGradientBrush;
}
}
}
6、现在打开MainPage.xaml.cs文件,添加如下的方法来对飞船和存在的所有外星人进行冲突检测:
CheckCollisions方法
private
void
CheckCollisions()
{
for
(
int
iAlien
=
0
; iAlien
<
_aliens.Count(); iAlien
++
)
{
if
(_aliens[iAlien].isAlive)
{
if
(_ship.CollidesWith(_aliens[iAlien]))
{
_aliens[iAlien].PaintGradient(Colors.Red, Colors.White);
_aliens[iAlien].isAlive
=
false
;
}
}
}
}
7、在RenderFrame方法的“CheckBounds();”语句的下面添加如下的代码:
CheckCollisions();
8、编译并运行本解决方案,运行效果图如下:
使用背景
创建一个继承自UpdateableUIElement的名称为BackgroundWrapper的子类。使用它来创建一个跟随飞船进行移动的光栅背景。这很容易,你现已具备这方面的知识来添加该背景。
总结
现在我们已经了解了高级的多精灵动画的绘制以及结合面向对象的设计来对游戏进行控制。我们将开始进行3D游戏的开发制作,这是下一章的话题。
代码下载:本章源代码