使用directX 7结合C#进行2D游戏编程

使用directX 7结合C#进行2D游戏编程

前言

对于C#的开发人员来讲,GDI+ 是一个拥有丰富的绘图API指令、传统、高效的程序集。但不幸的是,你要想用她来开发一个复杂而又平滑的动画的时候,我们会发现GDI+只能做到有限的快。因此,它是绝不适合做游戏开发;不要妄想你那飞快的处理器和崭新的、长着奇异形状的图形卡,到DirectX API来。

不幸的是,.net和C#并非DirectX的官方开发平台,但是DirectX 9可利用.net平台做为其标准开发平台,我们只需引用他的命令空间就可以了。不过我们要以利用VB7、8的DirectX组件在C#中进行开发。本文将利用一个简单的突围风格的游戏(我突发奇想的叫她做"太空突围")来示范在C#环境下,如何利用VB的DirectX的组件进行开发。

DirectX 和 DirectDraw

DirectX 8 之前,DirectDraw是DirectX的主要2D接口。自从windows主流的游戏编程偏离平面游戏时,Mircrosoft决定将2D和3D的API原理合并,新的接口称为DirectGraphics。这样做非常有好处,因为如果你想开发纯2D的游戏,哪他将没有任何3D的加速,这样总有些不好吧,大大的不好:-

l DirectGraphics需要一张3D加速卡做为2D的硬件加速

l DirectGraphics可直接绘制2D图形。DirectDraw则需要了解一些3D的概念

所以当开发纯2D游戏时依然可以首要考虑DirectDraw,在DirectX 8下依然可以建立DirectX 7(提供DirectDraw的版本)的对象。

设置DirectX程序

进行.net的DirectX开发,首先引用DirectX的COM dll文件。如何加入引用?在"项目"菜单中选择"添加引用",选择"COM",如果你已经安装了DirectX 7、8,你就能在"组件名称"中找到"DirectX 7 for Visual Basice Type Library"或"DirectX 8 for Visual Basice Type Library"。"选择"他们。DirectX程序在.net中必须基于winForm程序,所以,下一步要建立一个基本的无边框的winForm。

初始化DirectX

在《太空突围》的主DirectX对象及他们的初始化封装在GameDirectDrawClass类中。DirectDraw有两种显示模式:全屏和窗口模式。在DirectDraw的游戏开发中,全屏模式是最常用的,他可在游戏的全程独占屏幕作为用户的界面,他对故事的演绎、用户的投入程度,都要好优于windows模式。以下变量是GameDirectDrawClass类用于初始化全屏模式的(全文我都假定你已经在文件的头部加入了"using DxVBLib;"的语句)。

private DirectX7 m_objDirectX = new DirectX7();
private DirectDraw7 m_objDirectDraw;
private DirectDrawSurface7 m_objPrimarySurface;
private DirectDrawSurface7 m_objBackBufferSurface;
private DDSURFACEDESC2 m_objPrimarySurfaceDescription;
private DDSURFACEDESC2 m_objBackBufferSurfaceDescription;


变量m_objDirectX是游戏DirectX主对象的一个实例,另预先准备m_objDirectDraw是游戏主DirectDraw对象的一个实例。另两年变量(m_objPrimarySurface 和 m_objBackBufferSurface)是DirectDraw的Surface,所谓Surface就是代表我们实际作图的平面、纸张,就象GDI+的图形对象一般。

每个DirectDraw 程序都必须有最少一个Surface对象。Surface指向的是物理显存。经常的做法是建立一个主surface对象,这里是m_objPrimarySurface变量。除主surface对象之外,应有一些不显示的surface存在于内存中。作为第二种surface变量我们通常称为后缓存(m_objBackBufferSurface)。

后缓存surface在程序中是作为双重缓冲。双重缓冲的过程是这样的:我们在第二个surface中进行的一个帧的所有的绘图(译者:我们应有一个概念:每个surface就是动画中的其中一帧),当所有绘图动作完成后就可以将整个缓冲区拷贝到主surface。DirectDraw全屏下进行这种整页的拷贝工作称为page flipping(译者:我也喜欢将其译为"页翻转")。当页翻转时,主surface将指向BackBufferSurface的内存地址,而BackBuffer将指向主surface原指向的地址。这样一来,主surface包含Backbuffer的内容,BackBuffer对象也包含着主surface的内容。一次页翻转后,BackBuffer就会清掉缓存的内容,并进行下一帧的绘图工作。图2说明了这个过程。


这剩下的两个变量m_objPrimarySurfaceDescription、m_objBackBufferSurfaceDescription是用来设置一些道具的surface,将在下面详述。

InitialiseDirectXFullScreen()方法是GameDirectDraw类的用于初始化DirectDraw对象的。他有一个整形的参数,指向一个表单的句柄(handle)。代码如下:

InitialiseDirectXFullScreen(int objDisplayFormHandle)
{

m_objDirectDraw = m_objDirectX.DirectDrawCreate("");

m_objDirectDraw.SetCooperativeLevel (objDisplayFormHandle, CONST_DDSCLFLAGS.DDSCL_FULLSCREEN | CONST_DDSCLFLAGS.DDSCL_EXCLUSIVE);

m_objDirectDraw.SetDisplayMode(640, 480, 16, 0, CONST_DDSDMFLAGS.DDSDM_DEFAULT);

m_objPrimarySurfaceDescription.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_BACKBUFFERCOUNT;

m_objPrimarySurfaceDescription.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE |CONST_DDSURFACECAPSFLAGS.DDSCAPS_FLIP | CONST_DDSURFACECAPSFLAGS.DDSCAPS_COMPLEX;

m_objPrimarySurfaceDescription.lBackBufferCount = 1;

m_objPrimarySurface = m_objDirectDraw.CreateSurface(ref m_objPrimarySurfaceDescription);
DDSCAPS2 ddscaps = new DDSCAPS2();
ddscaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_BACKBUFFER;

m_objBackBufferSurfaceDescription = m_objPrimarySurface.GetAttachedSurface(ref ddscaps);
m_objBackBufferSurfaceDescription(ref m_objBackBufferSurfaceDescription);

}


在代码的第一行,建立了一个DirectX 7的对象。这DirectDraw对象调用了一次SetCooperativelevel()方法,设置DirectDraw对象与操作系统联合(co-operation)的水平。第一个参数是程序要用的form的句柄,第二个参数包含着一些标记(flags),指示程序所需的联合水平。这里我们用了两个标记,我们既要全屏又要独占显示控制。

下一个DirectDraw方法是SetDisplayMode()。他是用于设置屏幕属性,头两个参数指定分辨率为640*480,第三个指定为16Bit色,第四个是刷新率(这里设为0,DirectDraw将自动使用最好的分辨率)第五个指定没有高级分辨率使用(no advanced resolutions are to be used不明白)。

跟着的是对主surface 的描述变量(descriptor)的赋值,这变量将用来建立主surface。我们指定的这些标记将用来指定surface的容量和他的缓冲数,利用的是lflags的属性。下一行定义了surface的能力。头一变量指定了这将要是一个主surface,跟着的变量指定我们将要使用"页翻转",这最后的变量是我们使用"页翻转"而特定需要的。下一行定义了surface的缓冲数,这里指定了一个。定义设好后,我们利用DirectDraw对象的CreateSurface()方法建立主surface,该方法需要一个指向"描述变量"的参数。

当主surface建立后,BackBuffer也能建立了。我们设置相同的属性给BackBuffer的描述变量,并指定为一个后缓冲surface,于是我们就用主surface对象的GetAttachedSurface()方法建立这个BackBuffer。

显示位图

在DirectDraw中,位图必须加载到新的surface然后拷贝到BackBuffer。在游戏中,许多位图绘制代码都封装在抽象类BitmapObject中,所有游戏对象都继承自该抽象类。主变量使用BitmapObject类来建立位图对象,并把位图绘制在Backbuffer。

public const int BLACK_TRANSPARANT_SPRITE = 1;
public const int NORMAL_BITMAP = 0;

protected DDSURFACEDESC2 m_objDDSurfaceDescription;
private DirectDrawSurface7 m_objBitmapSurface;

protected RECT m_objSizeRECT;


前两行定义的两个常数用以区分对象是组图(sprite)还是位图。组图是指一些不规则的小图。另,m_objDDSurfaceDescription是一个surface的描述对象,用以为设置surface对象属性服务,m_objBitmapSurface是一个DirectDraw的surface对象,他代表着一个位图。剩下变量是一个RECT结构,是个矩形结构,他代表着surface的方形区域,surface用于拷贝缓冲区信息。

InitialiseSurfaceDescription(int intBitmapWidth, int intBitmapHeight) {

m_objDDSurfaceDescription.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT;

m_objDDSurfaceDescription.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN;

m_objDDSurfaceDescription.lWidth = intBitmapWidth;

m_objDDSurfaceDescription.lHeight = intBitmapHeight;

m_objSizeRECT.Bottom = intBitmapHeight;

m_objSizeRECT.Right = intBitmapWidth;

}


方法的第一行代码设置surface的描述对象的lFlags属性,他指定的性质将用于设置surface的属性、宽、高。跟着的代码设置了另surface的性质,这surface是非显示surface。一个非显示surface是指存在于内存中,而自身不显示给用户。接着的两行设置了surface的宽、高。最后两行设置一个RECT结构的宽、高。

每次surface的建立都要进行surface描述对象的设置,我们将这些代码放在了InitialiseSurface()方法中。这方法有三个参数,程序的DirectDraw对象、一个指向一个位图的字符串、一个整数(指针)指向将在被建立的位图、组图。方法代码如下:

InitialiseSurface(DirectDraw7 DirectDraw, string strBackgroundBitmap, int intBitmapType)
{
try
{
m_objBitmapSurface = DirectDraw.CreateSurfaceFromFile( strBackgroundBitmap,
ref m_objDDSurfaceDescription );

}
catch ( Exception e)
{
System.Windows.Forms.MessageBox.Show( "Unexpected exception: " + e.ToString(), "Unexpected Exception" );

System.Windows.Forms.Application.Exit();
}

switch (intBitmapType)
{

case BitmapObject.BLACK_TRANSPARANT_SPRITE:

DDCOLORKEY objBlackKey;

objBlackKey.low = 0; objBlackKey.high = 0;
m_objBitmapSurface.SetColorKey( CONST_DDCKEYFLAGS.DDCKEY_SRCBLT, ref objBlackKey);
break;
}

}


前一部分代码是利用一个位图文件来建立surface对象,他使用了DirectDraw对象的CreateSurfaceFromFile()方法。CreateSurfaceFromFile()有两个参数,一个是文件的字符串,另一个是需处理的surface的描述对象。

后一部分代码用于建立组图(sprite)。我早前说过,组图是不规则的一此小图,不幸的是,位图文件只能是方形的,所以DirectDraw只有将方形的图形转变成组图。过程是这样的:首先为surface定义一个颜色值,当surface装载到另一个surface时,DirectDraw将位图的什么该值颜色的位置换为透明。这游戏所有组图都用黑色值,第一行代码建立一个DirectDraw颜色对象,下两行定义了黑色中最高、最低值。接着调用位图surface对象的SetColorKey()。

DDCKEY_SRCBLT: 
Color key or color space to be used as a source color key for blit operations. 

source color key:
A color that (in the case of blitting) is not copied to, or (in the case of overlays) not visible on, the destination。

destination color key:
The color that (in the case of blitting) is replaced or (in the case of overlays) is covered on the destination surface.

位图surface建立后,就可加载到BackBuffer中,这种由一surface信息覆盖到另一surface的过程我们称之为"blitting"---"bit block transfer"(我称其为"字组转移")。为了字组转移我们定义BltFast()方法,以下是BltFast()的代码,用于从BitmapObject类转移组图到Backbuffer。

objBackBufferSurface.BltFast( this.XPosition, this.YPosition, m_objBitmapSurface, ref m_objSizeRECT, CONST_DDBLTFASTFLAGS.DDBLTFAST_SRCCOLORKEY | CONST_DDBLTFASTFLAGS.DDBLTFAST_WAIT );


第一个参数指出组图将要放的点距BackBuffer左边的点值,第二个参数是该点距Backbuffer顶边的点值;第三个参数是组图对象,第四个是定义了转移的区域大小的RECT结构,最后一个参数是转移的标志,这里所用的两个标志指明了我们要使用指定对象颜色值和DirectDraw必须要等待方法完成转换后才进行下一步的工作。

翻转BackBuffer到主surface

一个帧的所有位图转换完成后,BackBuffer就需要将其自身翻转到主surface。这项工作由GameDirectDraw类的FlopBackBufferAndPrimary()方法完成。该方法只有一行代码。

this.PrimarySurface.Flip(this.BackBufferSurface, CONST_DDFLIPFLAGS.DDFLIP_WAIT);


正如我们所看到的,主surface对象的Flip()方法被调用,他需要两年参数。第一个是BackBuffer对象,第二个要求DirectDraw等待翻转的完成。一次翻转完成,BackBuffer就会清除自身内容并进行下一个动画的转移。

Conclusion

This article has detailed the core elements of building a game using DirectX and DirectDraw. DirectX is a huge topic but it is hoped that in conjunction with the source code for the Space Breakout game youll have all you need to begin building your own 2D DirectX games.

译:

结论

本文详述了DirectX和DirectDraw建立一个游戏的主要原理。DirectX是一个庞大的话题,但我希望大家认真研究"空间突围"的代码,你将会学会开发DirectX 2D游戏所需要的知识。

http://www.cnblogs.com/ww21xx/articles/93740.html

你可能感兴趣的:(c++技术,c#基础概念,c#技术)