Sliverlight 3 3D 游戏开发学习 第三章:精灵与背景的结合

在本章,你将学会:
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.如下图所示:

Sliverlight 3 3D 游戏开发学习 第三章:精灵与背景的结合_第1张图片
  13、选择“缩放”选项卡,点击“使用相对值”并在X和Y文本框中输入0.5。
  14、回到XAML代码中,你将看到“Canvas.RenderTransform”和“TransformGroup”的代码。这是Expression Blend创建的。为RotateTransform指定其名称为“rotateSprite”,如下面的代码所示:
<RotateTransform x:Name="rotateSprite" Angle="0"/>
  15、对每个用户控件重复相同的操作,下面是GreenAlien的效果图:

Sliverlight 3 3D 游戏开发学习 第三章:精灵与背景的结合_第2张图片

创建一个特定的精灵管理类

  在创建了各个用户控件后,我们需要根据这些用户控件来对许多的精灵进行移动操作。现在,我们要创建一个超类来对大多数和用户控件作为精灵运行有关的公共操作进行管理。
  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、编译并运行本解决方案,效果图如下:

Sliverlight 3 3D 游戏开发学习 第三章:精灵与背景的结合_第3张图片
冲突检测

  当外星人和飞船接触后我们希望这些外星人显示出不同的颜色,为此我们将进行如下步骤:
  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、编译并运行本解决方案,运行效果图如下:

Sliverlight 3 3D 游戏开发学习 第三章:精灵与背景的结合_第4张图片
使用背景

  创建一个继承自UpdateableUIElement的名称为BackgroundWrapper的子类。使用它来创建一个跟随飞船进行移动的光栅背景。这很容易,你现已具备这方面的知识来添加该背景。

总结

  现在我们已经了解了高级的多精灵动画的绘制以及结合面向对象的设计来对游戏进行控制。我们将开始进行3D游戏的开发制作,这是下一章的话题。

代码下载:本章源代码

你可能感兴趣的:(Sliverlight 3 3D 游戏开发学习 第三章:精灵与背景的结合)