对于游戏编程而言,我也是个初学者,这个游戏编程入门系列的文章,就当作是我在学习游戏编程的笔记和阶段小结吧。我们先从最简单的“精灵”开始,暂时我们不需要考虑DirectX或是OpenGL,不需要考虑3维等等这些复杂情形,直接使用GDI+绘图功能就可以了。
精灵,是构成游戏中活动体(比如,飞机、野兽等游戏人物)的最基本单元,任何一个活动体都可以由一个或多个精灵组合而成,每个精灵都是一个对象实例,它能够绘制自己、移动(更复杂的还可以旋转)等等基本动作。
我让所有的精灵都实现ISprite接口,该接口如下:
对应的代码如下:
这个接口也许并不是完整的,随了实际的深入,可能还会有很多的元素添加进来,甚至CompassDirections枚举还可以进一步细分,但是ISprite已经有最基本“精灵”功能了。对于大多数简单的任务,我们已经可以给出ISprite的一个实现:
我们要特别注意Erase方法的实现,所谓Erase实际上就是用背景图对应的区域重新绘制精灵所在的区域表面--这种技巧在游戏编程中是最基本的技巧之一。
当精灵接收到游戏环境的时钟脉冲通知时,最常见的方法调用组合是:
所以,当时钟脉冲连续不断的到来时,我们就可以看到精灵在移动了,通过我们的游戏操纵杆或键盘我们可以调用目标精灵的SetDirection方法来指定其要移动的方向。
下篇文章,我们将基于ISprite构建一个最简单的游戏示例,在这个示例中,我们可以通过键盘的方向键来控制游戏中主角的移动。
精灵,是构成游戏中活动体(比如,飞机、野兽等游戏人物)的最基本单元,任何一个活动体都可以由一个或多个精灵组合而成,每个精灵都是一个对象实例,它能够绘制自己、移动(更复杂的还可以旋转)等等基本动作。
我让所有的精灵都实现ISprite接口,该接口如下:
对应的代码如下:
public
interface
ISprite
{
GraphicsGraphics{ set ;} // 绘制的设备
BitmapSource{ set ;} // 精灵表面位图
ImageBackgroundImage{ set ;} // 游戏背景
PointLocation{ get ;}
void Erase();
void Draw();
void SetDirection(CompassDirectionsdir);
void Move();
}
public enum CompassDirections
{
NotSet = 0 ,
North = 1 ,
NorthEast = 2 ,
East = 3 ,
SouthEast = 4 ,
South = 5 ,
SouthWest = 6 ,
West = 7 ,
NorthWest = 8
}
{
GraphicsGraphics{ set ;} // 绘制的设备
BitmapSource{ set ;} // 精灵表面位图
ImageBackgroundImage{ set ;} // 游戏背景
PointLocation{ get ;}
void Erase();
void Draw();
void SetDirection(CompassDirectionsdir);
void Move();
}
public enum CompassDirections
{
NotSet = 0 ,
North = 1 ,
NorthEast = 2 ,
East = 3 ,
SouthEast = 4 ,
South = 5 ,
SouthWest = 6 ,
West = 7 ,
NorthWest = 8
}
这个接口也许并不是完整的,随了实际的深入,可能还会有很多的元素添加进来,甚至CompassDirections枚举还可以进一步细分,但是ISprite已经有最基本“精灵”功能了。对于大多数简单的任务,我们已经可以给出ISprite的一个实现:
public
class
Sprite:ISprite
{
private CompassDirectionsdirection = CompassDirections.South;
#region ISprite成员
private Graphicsgraphics = null ;
public GraphicsGraphics
{
set
{
this .graphics = value;
}
}
private Bitmapsource = null ;
public BitmapSource
{
set
{
this .source = value;
}
}
private Pointlocation = new Point( 0 , 0 );
public PointLocation
{
get
{
return this .location;
}
}
#region BackgroundImage
private ImagebackgroundImage = null ;
public ImageBackgroundImage
{
set
{
this .backgroundImage = value;
}
}
#endregion
public void Erase()
{
Rectangleret = new Rectangle( this .location.X,Location.Y, this .source.Width, this .source.Height);
this .graphics.DrawImage( this .backgroundImage,ret,ret,GraphicsUnit.Pixel);
}
public void Draw()
{
this .graphics.DrawImage( this .source, this .location.X, this .location.Y);
}
public void SetDirection(CompassDirectionsdir)
{
this .direction = dir;
}
public void Move()
{
int stepSize = 5 ;
if ( this .direction == CompassDirections.South)
{
this .location.Y += stepSize;
return ;
}
if ( this .direction == CompassDirections.East)
{
this .location.X += stepSize;
return ;
}
if ( this .direction == CompassDirections.West)
{
this .location.X -= stepSize;
return ;
}
if ( this .direction == CompassDirections.North)
{
this .location.Y -= stepSize;
return ;
}
}
#endregion
}
{
private CompassDirectionsdirection = CompassDirections.South;
#region ISprite成员
private Graphicsgraphics = null ;
public GraphicsGraphics
{
set
{
this .graphics = value;
}
}
private Bitmapsource = null ;
public BitmapSource
{
set
{
this .source = value;
}
}
private Pointlocation = new Point( 0 , 0 );
public PointLocation
{
get
{
return this .location;
}
}
#region BackgroundImage
private ImagebackgroundImage = null ;
public ImageBackgroundImage
{
set
{
this .backgroundImage = value;
}
}
#endregion
public void Erase()
{
Rectangleret = new Rectangle( this .location.X,Location.Y, this .source.Width, this .source.Height);
this .graphics.DrawImage( this .backgroundImage,ret,ret,GraphicsUnit.Pixel);
}
public void Draw()
{
this .graphics.DrawImage( this .source, this .location.X, this .location.Y);
}
public void SetDirection(CompassDirectionsdir)
{
this .direction = dir;
}
public void Move()
{
int stepSize = 5 ;
if ( this .direction == CompassDirections.South)
{
this .location.Y += stepSize;
return ;
}
if ( this .direction == CompassDirections.East)
{
this .location.X += stepSize;
return ;
}
if ( this .direction == CompassDirections.West)
{
this .location.X -= stepSize;
return ;
}
if ( this .direction == CompassDirections.North)
{
this .location.Y -= stepSize;
return ;
}
}
#endregion
}
我们要特别注意Erase方法的实现,所谓Erase实际上就是用背景图对应的区域重新绘制精灵所在的区域表面--这种技巧在游戏编程中是最基本的技巧之一。
当精灵接收到游戏环境的时钟脉冲通知时,最常见的方法调用组合是:
theSprite.Erase();
theSprite.Move();
theSprite.Draw();
首先,精灵擦除自己,然后依据方向CompassDirections移动自己到新的位置,最后在新的位置绘制自己。
theSprite.Move();
theSprite.Draw();
所以,当时钟脉冲连续不断的到来时,我们就可以看到精灵在移动了,通过我们的游戏操纵杆或键盘我们可以调用目标精灵的SetDirection方法来指定其要移动的方向。
下篇文章,我们将基于ISprite构建一个最简单的游戏示例,在这个示例中,我们可以通过键盘的方向键来控制游戏中主角的移动。