佳礼资讯网

 找回密码
 注册

ADVERTISEMENT

查看: 7045|回复: 68

使用C# + Managed DIrectX 制作 2D 游戏

[复制链接]
发表于 14-5-2008 02:42 PM | 显示全部楼层 |阅读模式
主旨:虽然目前Microsoft已经发布了XNA Game Studio,让游戏编程员能够更轻松的在Windows(XB360不在本文考虑范围内)制作游戏,不过这个XNAGS有个缺点,它要求系统必须有至少能够支援Shader Model 1.1的显示卡。这表示TNT,GeForce 1, 2, 和 GeForce 3 & 4 MX 系列的显示卡,以及较早期的 integrated display 都无法执行XNAGS本身,以及XNAGS所制作出来的游戏。在这些配备下,就算你打算制作的游戏根本不需要使用Shader (2D 游戏,或画面要求不高的 3D 游戏, 如一般的 online 游戏之类的), 你也无法使用XNAGS来开发你的游戏。无论如何,我相信在本地,不支援shader的电脑还大有市场,所以就开始研究如何在没有shader支援的环境下,使用C# + DirectX 来制作游戏,结果这篇分享文就这样诞生了。

何谓Managed DirectX? 在,NET盛行之前,想要编写DX游戏就得和臭名昭彰的COM打交道。COM(component object model)是一个颇为复杂的编程界面,它提倡所有物件都采用相同的interface,以便达到新版本都能对下兼容,却不必担心界面的改变而必须从新学习这些interface。COM带来的问题是,编程员需要记忆大量的interface的各种overloaded版本,令人头痛不已。

在.net framework之下的Managed DX 概念则是提供一个容易referance各种object,同时也提供了一些自动化的资源管理功能,以及以更简洁的指令执行原本很复杂的运作。在接下来的sample之中,有过使用COM版本DX经验的人会感到惊奇,原来使用 Managed DX 竟然变得如此简单!

文章对象:中等程度的 C# 或 C++ 经验(C++和C#的语言结构很接近,所以 C++ 编程员应该不难理解 C# 的 code),有过 Direct X 编程经验更佳。

软/硬件需求:
1)一台能够运行 Windows XP 的电脑,
2)Microsoft Visual C# 2005 Express Edition (2008 亦可)(可在Microsoft Developers Network 免费下载)(不需要XNAGS)(我使用的是 2005 版本)
3)Microsoft DirectX 9.0 SDK  March 2007 或更新的版本(注意这不是一般安装游戏时发布的 Runtime 版本)(可在MSDN下载,免费)(我使用的是March 2008 版本)
4)一张至少能够运行DIrect X 9.0 版游戏的显示卡(我的开发电脑装备的是GeForce 2 MX 32MB)
5)一颗强壮的心,钢铁般的意志,对游戏开发和学习编程有强烈的兴趣。哦,还有超强的吸收力。。。

《待续》
回复

使用道具 举报


ADVERTISEMENT

 楼主| 发表于 14-5-2008 03:42 PM | 显示全部楼层
安装好 Visual C# Express Edition 和 Direct X 9.0 SDK 后,在 VC# 开启一个新的 project:
File->New Project...
这时一个Dialog会弹出来,让你选择你想要的 project 类型。我们选择 Empty Project,project name 就用 My2DGame 吧(或者你自行选择)。决定之后,就会看到右手边,Solution Explorer 已经打开你的新 project。现在里面是空空的,只有一个References在你的Project 里面。现在,在References上Right Click, 然后选Add References... 然后就会有个Dialog, 显示你的电脑里已经安装了的,可以Reference的components。 我们要加入的是.NET的components:
System
System.Data
System.Drawing
System.Windows.Form
Microsoft.DirectX
Microsoft.DirectX.Direct3D
Microsoft.DirectX.Direct3DX
Microsoft.DirectX.DirectInput
Microsoft.DirectX.DIrectSound

暂时就这几个。

接下来,加入你的source code file。在Solution Explorer里面,right click你的Project name (例如 My2DGame)然后选择 Add->New Item... 在打开的Dialog里面选择 Code File, 命名为 My2DGame.cs。

接下来,左边就会显示一个空的 Code Editor。如果你关闭了这个Editor, 你只需 right click 那个新加入的 My2DGames.cs,选择 View Code,就可以打开这个 code file。

现在我们要正式开工了,在那个空荡荡的 My2DGame.cs 的 code file 里面输入你要使用的 component 的 using statement:
  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. using Microsoft.DirectX;
  5. using Microsoft.DirectX.Direct3D;
  6. using Microsoft.DirectX.DirectInput;
  7. using Microsoft.DirectX.DirectSound;

  8. namespace My2DGame
  9. {
  10. }
复制代码
接下来,我们要开启一个新的Windows Form:
  1. namespace My2DGame
  2. {   
  3.     public class Game : Form
  4.     {
  5.         public Game()
  6.         {
  7.             this.ClientSize = new Size(800, 600);
  8.             this.Text = "The Game - Managed DirectX";
  9.         }
  10.         static void Main()
  11.         {
  12.             using (Game MainForm = new Game())
  13.             {
  14.                 if (!MainForm.InitD3D())
  15.                 {
  16.                     MessageBox.Show("Failed to initialize Direct 3D Device");
  17.                     return;
  18.                 }
  19.                 MainForm.Show();

  20.                 while (MainForm.Created)
  21.                 {
  22.                     MainForm.UpdateGame();
  23.                     Application.DoEvents();
  24.                 }
  25.             }
  26.         }
  27.     }
  28. }
复制代码
以上就是你的 Form Class 和 Constructor。没错,在C#里面Create Windows Form 就是这么简单。后面接着来的就是这个 Program 的 Main() 以及初始化 Direct3D的Function call,和游戏循环(loop)。咦?我们不是要设计2D游戏吗?为何要启动Direct3D呢?其实,在DX8的时候就已经废除了2D 的 DirectDraw 了,现在的DX虽然还包含 DirectDraw 这个零件,但是那只是为了对下兼容以前的DD软件,事实上DD已经没有再更新了。现在,取代DD的就是 DirectX 9 Graphics 这个部件,它是以最简单的D3D功能模拟了2D环境,并且提供了更多样化的画面渲染方式,以让2D游戏能够以更华丽的方式呈现出来(DX9 Graphics 包含了一部分的3D功能,例如Scaling, rotating, tinting 等, 只是这些功能都是在X-Y轴上运算,忽略掉Z-轴运算),同时能够善用3D硬件的强大又快速的运算好处。

《待续》

[ 本帖最后由 geekman 于 14-5-2008 03:48 PM 编辑 ]
回复

使用道具 举报

 楼主| 发表于 14-5-2008 05:33 PM | 显示全部楼层
先别急着执行这个Program,你一定会遇到很多error的,因为还有很多东西没放进去。现在,在 class Game:Form{}里面,在顶端加入以下的object/variable declaration:
  1. //--Graphics--
  2. Microsoft.DirectX.Direct3D.Device d3dev = null;
  3. Sprite sprite;
  4. Texture myTexture;
  5. Vector3 ctr;
  6. Vector3 pos = new Vector3(400.0f, 300.0f, 0.0f);
  7. float angle = 0.0f;

  8. Matrix transformmatrix, rotatematrix, finalmatrix;
  9. //--input----
  10. Microsoft.DirectX.DirectInput.Device kb;
复制代码
Direct3D.Device 代表了你的显示卡,也代表了你的绘图空间。Sprite 则是DX9 Graphics的灵魂所在,它提供了一系列的运算和绘画功能,让你可以轻松的把想呈现在荧幕上的画面画出来。Texture就是一般3D游戏中贴在3D模型上的材质,在这里,它成了你的物件的图像的寄身所在。在DX9 Graphics里面,每一个Sprite事实上是一个平面的正方形polygon,其normal永远和z-轴平行(就像以前Doom 2 时代的 Billboard object 一般永远对着镜头。只在这里,我们的镜头也是永远不变的跟z-轴平行着的),其画像就是贴在上面的Texture了。Vector3是一个从起源点(Origin, X=0, Y=0, Z=0),发射向某个点(X=nx, Y=ny, Z=nz)的假想线。在2D 环境下,我们可以把它当作一个点(point),因为我们只对其X和Y值有兴趣(Z值无视),我们有两个Vector3,pos和ctr。pos是用来代表我们的Sprite在这个2D空间的位置,ctr则是Sprite的中心点。为何要使用中心点呢?那是因为,如果你要使用Sprite的Origin(X=0, Y=0)来代表它的位置的话,你得同时keep track 它的宽和高,十分麻烦,而使用中心点的话,你只需注意一个point,方便很多。pos被设定为 X=400,Y=300,正处在画面中间(我们的画面,也就是Direct3D.Device.Viewport, 会被设定为 800x600)

Matrix 是用来进行transfrmation的,例如旋转(rotation),放大缩小(scaling),以及转移位置(translation)。Sprite 的Transformation功能有个Bug, 导致任何Sprite.Rotation 的运算都会以viewport的(0,0)作为中心点,而忽略了你所选择的中心点(例如 X=400, Y=300),所以我们不能使用Sprite的回旋功能。其解决方法就是使用两个transformation,先 rotate 再 translate 到你想要的位置。

之后就是Keyboard device, 在这个范例里面,我只打算使用keyboard, Mouse的使用方法和Keyboard相似,只是更简单(两轴+3个按钮+1个wheel)。

接下来是启动和初始化Direct3D。
  1. public bool InitD3D()
  2. {
  3.     try
  4.     {
  5.         PresentParameters pp = new PresentParameters();
  6.         pp.Windowed = false;
  7.         pp.BackBufferWidth = 800;
  8.         pp.BackBufferHeight = 600;
  9.         pp.SwapEffect = SwapEffect.Discard;
  10.         pp.BackBufferFormat = Format.A8R8G8B8;

  11.         d3dev = new Microsoft.DirectX.Direct3D.Device(0,
  12.                        Microsoft.DirectX.Direct3D.DeviceType.Hardware,
  13.                        this,
  14.                        CreateFlags.SoftwareVertexProcessing,
  15.                        pp);

  16.         sprite = new Sprite(d3dev);
  17.         myTexture = TextureLoader.FromFile(d3dev, "mypic.png");
  18.         System.Drawing.Image bmp = System.Drawing.Image.FromFile("mypic.png");
  19.         ctr = new Vector3(bmp.Width / 2, bmp.Height / 2, 0.0f);

  20.         kb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
  21.         kb.SetCooperativeLevel(this,
  22.                                CooperativeLevelFlags.NonExclusive |
  23.                                CooperativeLevelFlags.Background);
  24.         kb.Acquire();

  25.         return true;
  26.    }
  27.    catch (DirectXException)
  28.    {
  29.        return false;
  30.    }
  31. }
复制代码
PresentParameters (发音 Pri-sent,“呈现”的意思)是用来决定Direct3D如何描绘画面的设定的structure。pp.Windowed决定你的游戏是Full Screen还是Windowed。要注意的是,如果你把Windowed设定为true,所有关于backbuffer的设定将会被无视,而viewport size和color depth将会跟随现有windows的Client Size和deskto color depth。BackBuffer Format采用Alpha8, Red8, Green8, Blue8,表示Sprite可以有256阶段的透明度(8-bit Alpha)。如果你的BackBuffer Format选择了错误的设定,会导致你的D3D初始化失败的,要注意。设定好PresentParameters 后就可以制造一个D3D Device了。其Argument如下:
  1. Microsoft.DirectX.Direct3D.Device(
  2. 0, //adapter id, 0 for default, 也就是你的主显示卡
  3. Microsoft.DirectX.Direct3D.DeviceType.Hardware, //如果你的显示卡友支援完整的DX9功能,你可以使用硬体加速,不然就只能使用软件模拟(很慢的)
  4. this, //这个游戏的视窗本身                          
  5. CreateFlags.SoftwareVertexProcessing, //不支援Shader的显示卡只能使用软件模拟的VP了
  6. pp //PresentParameter
  7. );
复制代码
接下来是制造Sprite和Texture物件,由于它们都会用到D3D Device物件,所以必须在制造了D3D Device 才能制造这两个物件。在制造Texture物件前,你得先把一个图画加入在project里面,作为Texture的画像。Right click Solution Explorer里面的Project Name, 然后选择 Add->Existing Item...,选择一个你要当作图像的图画(BMP, JPG, PNG, GIF, WMF, EMF 等格式)我个人喜欢使用PNG格式,因为它支援透明背景,同时也不会像BMP般占大量空间,却也不会像JPG般压缩了之后会出现边缘模糊的情形。记着你的图形最好是正方形,而且尺寸必须是2的倍数(2,4,8,16,32,64,128,256。。。。),不然D3D会把你的图画缩小到最近似的2的倍数,例如你的图画是300x300的话,会被缩小成256x256。而在某些function中,不是2的倍数的texture尺寸会导致function fail。

然后我们通过一个Bitmap object来获取texture图像的尺寸(奇怪的是我无法通过Texture object来获得这些讯息, 有知道如何直接从Texture object获得图像来源的尺寸的高手请指教),一边计算出Texture的中心点。最后,我们制造一个键盘物件,并通过SetCooperativeLevel设定其运作个性(Behavior),以避免当玩家按 Alt-Tab 跳回桌面时,游戏仍然死抓着键盘控制权不放,造成操作上的不便。Acquire() 是确定键盘处在准备妥当的状态(没有别的program正在抓着键盘控制权)。如果这个初始化function出现问题,就会return false,反之,就会return true。

《待续》

[ 本帖最后由 geekman 于 15-5-2008 11:13 AM 编辑 ]
回复

使用道具 举报

发表于 14-5-2008 05:49 PM | 显示全部楼层
yay 我第一个来支持你了
回复

使用道具 举报

 楼主| 发表于 14-5-2008 06:17 PM | 显示全部楼层
下一步,就是游戏的内容更新,这个Function的作用是读取玩家的输入(键盘,滑鼠,gamepad, joystick, 驾驶盘,诸如此类),根据输入进行计算(移动玩家角色,计算AI,刷新NPC状态(活着,移动中,死亡),刷新游戏世界状态,描绘HUD等等),然后将计算后的结果描绘成下一个Frame,最后呈现在荧幕上。
  1. public void UpdateGame()
  2.         {
  3.             KeyboardState ks = kb.GetCurrentKeyboardState();
  4.             if (ks[Key.Escape])
  5.             {
  6.                 this.Close();
  7.                 return;
  8.             }
  9.             if (ks[Key.A])
  10.             {
  11.                 pos.X -= 5;
  12.                 if (pos.X < 0)
  13.                     pos.X = 0;
  14.             }
  15.             if (ks[Key.D])
  16.             {
  17.                 pos.X += 5;
  18.                 if (pos.X > d3dev.Viewport.Width)
  19.                     pos.X = d3dev.Viewport.Width;

  20.             }
  21.             if (ks[Key.W])
  22.             {
  23.                 pos.Y -= 5;
  24.                 if (pos.Y < 0)
  25.                     pos.Y = 0;
  26.             }
  27.             if (ks[Key.S])
  28.             {
  29.                 pos.Y += 5;
  30.                 if (pos.Y > d3dev.Viewport.Height)
  31.                     pos.Y = d3dev.Viewport.Height;
  32.             }
  33.             angle+=0.1f;
  34.             if (angle >= 360)
  35.             {
  36.                  angle = 0;
  37.             }
  38.             Render();
  39.         }
复制代码
以上Function我只检测键盘的5个键:WASD 移动物件(Sprite)的 pos,Escape键结束游戏。要注意的是,UpdateGame 里面就只纯粹更新状态,别把描绘的工作掺杂在里面,以免你无法迅速的完成工作而导致游戏出现控制反应迟缓的现象。

最后,把游戏状态描绘成画面,然后呈现在荧幕:
  1. public void Render()
  2.         {
  3.             d3dev.Clear(ClearFlags.Target, Color.SkyBlue, 1.0f, 0);
  4.             d3dev.BeginScene();
  5.                 sprite.Begin(SpriteFlags.AlphaBlend);
  6.                     rotatematrix.RotateZ(angle);
  7.                     transformmatrix.Translate(pos);
  8.                     finalmatrix = Matrix.Multiply(rotatematrix, transformmatrix);
  9.                     sprite.Transform = finalmatrix;
  10.                     sprite.Draw(myTexture, Rectangle.Empty, ctr, Vector3.Empty, Color.White);
  11.                 sprite.End();
  12.             d3dev.EndScene();
  13.             d3dev.Present();
  14.         }
复制代码
首先清空画面,填上Color.xxxx 的颜色。然后就启动D3D Device的描绘机制,当你呼叫Device.Begin()时,系统就会自动的锁定你的Frame Buffer(显示卡里面属于你的游戏的记忆空间),以免被其它程式,或你的游戏里的其他Thread (如果你采用 Multi Threaded 设计)干扰。Sprite本身也采用类似的locking来锁定自己的Texture Buffer。 SpriteFlags.AlphBlend是告诉显示卡,我们要使用Alph channel, 来制造出透明效果。由于Sprite的Bug,我们不能使用它内建的Rotation功能,所以我们使用了两个Matrix,把它们Multiply起来,再直接把结果set在Sprite.Transformation, Sprite 就会乖乖的完成你指定的变形(以 X=400,Y=300 为中心点,绕着自己的中心缓缓的旋转)。End()指令告诉显示卡,你已经完成工作,可以解开Frame Buffer的锁定。Present()就是Flip Buffer, 因为这游戏是 Double-buffered 的,也是说它有两个Frame Buffer,一个在前也就是显示在荧幕上的Front Buffer, 另一个是在荧幕显示之外的 Back Buffer。你的一切更新都是在 Back Buffer 里进行的,当完成更新之后,Present() 就会把两个Buffer调换,荧幕上就会显示出最新的画面,而你就继续将已经过时了的画面清掉,描绘下一个画面。这么做得好处是你不必等待荧幕刷新时才能进行描绘,而且也能避免画面撕扯(tearing)的现象。

好了,现在你已经有了一个2D游戏的雏形,接下来就发挥你的创作力,写一个游戏出来吧。
以下是整个Program的原始码:
  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. using Microsoft.DirectX;
  5. using Microsoft.DirectX.Direct3D;
  6. using Microsoft.DirectX.DirectInput;
  7. using Microsoft.DirectX.DirectSound;

  8. namespace My2DGame
  9. {
  10.     public class Game : Form
  11.     {
  12.         public Game()
  13.         {
  14.             this.ClientSize = new Size(800, 600);
  15.             this.Text = "The Game - Managed DirectX";
  16.         }
  17.         //--Graphics---
  18.         Microsoft.DirectX.Direct3D.Device d3dev = null;
  19.         Sprite sprite;
  20.         Texture myTexture;
  21.         Vector3 ctr;
  22.         Vector3 pos = new Vector3(400.0f, 300.0f, 0.0f);
  23.         float angle = 0.0f;

  24.         Matrix transformmatrix, rotatematrix, finalmatrix;
  25.         //--input---
  26.         Microsoft.DirectX.DirectInput.Device kb;

  27.         public bool InitD3D()
  28.         {
  29.             try
  30.             {
  31.                 PresentParameters pp = new PresentParameters();
  32.                 pp.Windowed = false;
  33.                 pp.BackBufferWidth = 800;
  34.                 pp.BackBufferHeight = 600;
  35.                 pp.SwapEffect = SwapEffect.Discard;
  36.                 pp.BackBufferFormat = Format.A8R8G8B8;
  37.                
  38.                 d3dev = new Microsoft.DirectX.Direct3D.Device(0,
  39.                     Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
  40.                     CreateFlags.SoftwareVertexProcessing, pp);

  41.                 sprite = new Sprite(d3dev);
  42.                 myTexture = TextureLoader.FromFile(d3dev, "mypic.png");
  43.                 System.Drawing.Image bmp = System.Drawing.Image.FromFile("mypic.png");
  44.                 ctr = new Vector3(bmp.Width / 2, bmp.Height / 2, 0.0f);

  45.                 kb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
  46.                 kb.SetCooperativeLevel(this,
  47.                                        CooperativeLevelFlags.NonExclusive |
  48.                                        CooperativeLevelFlags.Background);
  49.                 kb.Acquire();

  50.                 return true;
  51.             }
  52.             catch (DirectXException)
  53.             {
  54.                 return false;
  55.             }

  56.         }

  57.         static void Main()
  58.         {
  59.             using (Game MainForm = new Game())
  60.             {
  61.                 if (!MainForm.InitD3D())
  62.                 {
  63.                     MessageBox.Show("Failed to initialize Direct 3D Device");
  64.                     return;
  65.                 }
  66.                 MainForm.Show();

  67.                 while (MainForm.Created)
  68.                 {
  69.                     MainForm.UpdateGame();
  70.                     Application.DoEvents();
  71.                 }
  72.             }
  73.         }
  74.         public void UpdateGame()
  75.         {
  76.             KeyboardState ks = kb.GetCurrentKeyboardState();
  77.             if (ks[Key.Escape])
  78.             {
  79.                 this.Close();
  80.                 return;
  81.             }
  82.             if (ks[Key.A])
  83.             {
  84.                 pos.X -= 5;
  85.                 if (pos.X < 0)
  86.                     pos.X = 0;
  87.             }
  88.             if (ks[Key.D])
  89.             {
  90.                 pos.X += 5;
  91.                 if (pos.X > d3dev.Viewport.Width)
  92.                     pos.X = d3dev.Viewport.Width;

  93.             }
  94.             if (ks[Key.W])
  95.             {
  96.                 pos.Y -= 5;
  97.                 if (pos.Y < 0)
  98.                     pos.Y = 0;
  99.             }
  100.             if (ks[Key.S])
  101.             {
  102.                 pos.Y += 5;
  103.                 if (pos.Y > d3dev.Viewport.Height)
  104.                     pos.Y = d3dev.Viewport.Height;
  105.             }
  106.             angle+=0.1f;
  107.             if (angle >= 360)
  108.             {
  109.                 angle = 0;
  110.             }
  111.             Render();
  112.         }
  113.         public void Render()
  114.         {
  115.             d3dev.Clear(ClearFlags.Target, Color.SkyBlue, 1.0f, 0);
  116.             d3dev.BeginScene();
  117.                 sprite.Begin(SpriteFlags.AlphaBlend);
  118.                     rotatematrix.RotateZ(angle);
  119.                     transformmatrix.Translate(pos);
  120.                     finalmatrix = Matrix.Multiply(rotatematrix, transformmatrix);
  121.                     sprite.Transform = finalmatrix;
  122.                     sprite.Draw(myTexture, Rectangle.Empty, ctr, Vector3.Empty, Color.White);
  123.                 sprite.End();
  124.             d3dev.EndScene();
  125.             d3dev.Present();
  126.         }
  127.     }
  128. }
复制代码
回复

使用道具 举报

 楼主| 发表于 14-5-2008 06:22 PM | 显示全部楼层
原帖由 tensaix2j 于 14-5-2008 05:49 PM 发表
yay 我第一个来支持你了


呵呵呵,谢谢。对于 C# 我还在摸索阶段,很多东西都还没弄清楚(例如using, namespace 等是什么意思我也不懂 我只是把它当作新款式的C++来用。。。),所以各位高手看到有什么不对的请多多指教~
回复

使用道具 举报

Follow Us
发表于 14-5-2008 07:32 PM | 显示全部楼层
microsoft的directx最令人討厭的地方是
每次新version的都會phase out掉一些舊version的東西
結果讓舊的東西不能夠compile了

言歸主題
managed directx的code看起來干凈多了
我最討厭win32所用的hungarian notation
看到我昏
可以考慮學C# + Managed DirectX
新一代DirectX 10聽說滿不錯下
microsoft重金聘請了些很出名的programmer來打造的
回复

使用道具 举报

发表于 14-5-2008 09:52 PM | 显示全部楼层
原帖由 geekman 于 14-5-2008 06:22 PM 发表


呵呵呵,谢谢。对于 C# 我还在摸索阶段,很多东西都还没弄清楚(例如using, namespace 等是什么意思我也不懂 我只是把它当作新款式的C++来用。。。),所以各位高手看到有什么不对的请多多指教~


namespace 就是把一群related的 东西 grp 在一起, 这样就可以避免 class name,或 variable name clashing 的问题
using 就是 帮助 略省 写那么长的namespace。。。
回复

使用道具 举报


ADVERTISEMENT

发表于 14-5-2008 10:17 PM | 显示全部楼层

回复 8# tensaix2j 的帖子

簡單來說就跟java的package和import statement是一樣的東西來的
回复

使用道具 举报

 楼主| 发表于 15-5-2008 11:24 AM | 显示全部楼层
我现在正在考虑是否要继续扩展这个 2D Framework 成为一个完整的游戏范例。不知道自己是否有足够的时间和热情继续下去。。。C# + MDX 真的是越用越爱不释手

其实 MDX 也已经算是被 MS 所遗弃的了,MS 现在将精力集中在 XNAGS,MDX 只是他们开发 XNA 的过渡产品,不过 MDX 现在的状况已经足够自给自足,要用它来开发游戏也不是问题的。
回复

使用道具 举报

发表于 22-5-2008 12:35 PM | 显示全部楼层
一定要有Graphic Card才能运行吗??
我的只是32bit color 的而已。。
我运行时显示Failed to initialized DirectX 3D Device!
很想学咧~
回复

使用道具 举报

 楼主| 发表于 22-5-2008 04:21 PM | 显示全部楼层
我用来写这些 code 的电脑装备的是 GeForce 2 MX (现在 GeForce 已经去到第九代了,十代已经公布规格了),已经可以使用 Hardware Processing (只要有支援 Transform & Lighting 的卡就能使用了,也就是说第一代的 GeForce 理论上也可以执行 DX9 Graphics)。如果你的显示卡是 built in 的显示卡就有很大可能性不能运行。你可以尝试运行 Direct X 的测试工具 (在XP的电脑上点 Start -> Run...,然后在指令栏输入 dxdiag 就可以启动 Direct X 测试工具)来判定你的显示卡是什么款式。现在一张普通的 3D 显示卡(可以支援 DX9 的)也不过 RM100上下,我看过一张AGP 8x 的 Radeon 9250 也不过 RM85,这张显示卡已经足够应付 DX9 Graphics,甚至在我的下一个文章(正在研究中):Managed DirectX 3D graphics 也足够应付了。
回复

使用道具 举报

 楼主| 发表于 22-5-2008 04:41 PM | 显示全部楼层
我决定了要编写一个实际的游戏作为范例,游戏的类型是射击游戏(STG,又称 Shoot 'em up,或者Shmup),是一个直向射击游戏,像经典的1943那种的。

下面是我改写了之后的程式码,主要是把 Game Initialization 分成 Graphics Device 和 Keyboard,Mouse 以及 DirectSound 将会在以后用到时再加进去。然后加入了一个Struct, 作为游戏里的 “角色” ,包括玩家的飞机和敌人的雏形(目前 Actor 的设计比较偏向作为玩家的战机的设定,将来要套用在敌人身上时会做一些更改)。这个 Actor 的功能会在需要用到时再增加、扩充。目前的功能有:回转(承续自前一个demo的功能,目前没有实际用途,所以处在半废置状态),染色,透明化,自我移动范围规制,根据键盘输入而移动等。

接下来的讨论将会趋向于游戏设计,和解决各种设计游戏时将面对的问题。
  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4. using Microsoft.DirectX;
  5. using Microsoft.DirectX.Direct3D;
  6. using Microsoft.DirectX.DirectInput;
  7. using Microsoft.DirectX.DirectSound;

  8. namespace My2DGame
  9. {
  10.     public class Game : Form
  11.     {
  12.         Microsoft.DirectX.Direct3D.Device d3dev = null;
  13.         Microsoft.DirectX.DirectInput.Device kb = null;

  14.         Actor player;
  15.         Sprite sprite;

  16.         int errorNo;

  17.         public struct Actor
  18.         {
  19.             Vector3 pos;
  20.             Vector3 ctr;
  21.             Texture texture;
  22.             Matrix rotMatrix, transMatrix, finalMatrix;            
  23.             int speed;
  24.             uint alpha, tint, spcolor;
  25.             Rectangle boundingRect;
  26.             int powerLevel;

  27.             public Actor(Microsoft.DirectX.Direct3D.Device device)
  28.             {
  29.                 pos = new Vector3(device.Viewport.Width / 2, device.Viewport.Height / 1.2f, 0.0f);         
  30.                 texture = TextureLoader.FromFile(device, "plane.dds");
  31.                
  32.                 ctr = new Vector3(32.0f, 32.0f, 0.0f);
  33.                 speed = 5;
  34.                 rotMatrix = new Matrix();
  35.                 transMatrix = new Matrix();
  36.                 finalMatrix = new Matrix();

  37.                 boundingRect = new Rectangle(32, 32, (device.Viewport.Width - 64), (device.Viewport.Height - 64));
  38.                 alpha = 0xff000000;
  39.                 tint = 0xffffff;
  40.                 spcolor = alpha | tint;
  41.                 powerLevel = 1;
  42.             }

  43.             public void Rotate(float angle)
  44.             {               
  45.                 rotMatrix.RotateZ(angle);
  46.                 transMatrix.Translate(pos);                                
  47.                 finalMatrix = Matrix.Multiply(rotMatrix, transMatrix);
  48.             }

  49.             public void Move(int hDir, int vDir)
  50.             {
  51.                 if (hDir > 0)
  52.                 {
  53.                     pos.X += speed;
  54.                     if (pos.X > boundingRect.Right)
  55.                         pos.X = boundingRect.Right;
  56.                 }
  57.                 else if (hDir < 0)
  58.                 {
  59.                     pos.X -= speed;
  60.                     if (pos.X < boundingRect.Left)
  61.                         pos.X = boundingRect.Left;
  62.                 }
  63.                
  64.                 if (vDir > 0)
  65.                 {
  66.                     pos.Y += speed;
  67.                     if (pos.Y > boundingRect.Bottom)
  68.                         pos.Y = boundingRect.Bottom;
  69.                 }
  70.                 else if (vDir < 0)
  71.                 {
  72.                     pos.Y -= speed;
  73.                     if (pos.Y < boundingRect.Top)
  74.                         pos.Y = boundingRect.Top;
  75.                 }
  76.             }

  77.             public void DrawSprite(Sprite sp)
  78.             {
  79.                 sp.Draw(texture, ctr, pos, unchecked((int)spcolor));
  80.             }

  81.             public void setAlpha(uint newAlpha)
  82.             {
  83.                 alpha = newAlpha;
  84.                 spcolor = alpha | tint;
  85.             }

  86.             public void setTint(uint newTint)
  87.             {
  88.                 tint = newTint;
  89.                 spcolor = alpha | tint;
  90.             }

  91.             public void fire()
  92.             {
  93.                 switch (powerLevel)
  94.                 {
  95.                     case 1:
  96.                             break;
  97.                     case 2:
  98.                             break;
  99.                 }
  100.             }
  101.         }        

  102.         public Game()
  103.         {
  104.             this.ClientSize = new Size(800, 600);
  105.             this.Text = "My 2D Game with Managed DirectX";         
  106.         }

  107.         public bool InitD3D()
  108.         {
  109.             try
  110.             {
  111.                 PresentParameters pp = new PresentParameters();
  112.                 pp.Windowed = false;
  113.                 pp.BackBufferWidth = 800;
  114.                 pp.BackBufferHeight = 600;
  115.                 pp.BackBufferFormat = Format.A8R8G8B8;
  116.                 pp.SwapEffect = SwapEffect.Discard;

  117.                 d3dev = new Microsoft.DirectX.Direct3D.Device(0,
  118.                             Microsoft.DirectX.Direct3D.DeviceType.Hardware,
  119.                             this,
  120.                             CreateFlags.HardwareVertexProcessing,
  121.                             pp);

  122.                 return true;
  123.             }
  124.             catch (DirectXException)
  125.             {
  126.                 errorNo = DirectXException.LastError;
  127.                 return false;
  128.             }
  129.         }

  130.         public bool InitKeyboard()
  131.         {
  132.             try
  133.             {
  134.                 kb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
  135.                 kb.SetCooperativeLevel(this, CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background);

  136.                 kb.Acquire();
  137.                 return true;
  138.             }
  139.             catch(DirectXException)
  140.             {
  141.                 errorNo = DirectXException.LastError;
  142.                 return false;
  143.             }
  144.         }

  145.         public void UpdateGame()
  146.         {
  147.             KeyboardState ks = kb.GetCurrentKeyboardState();

  148.             if (ks[Key.Escape])
  149.             {
  150.                 this.Close();
  151.                 return;
  152.             }
  153.             if (ks[Key.Space])
  154.             {
  155.                 player.fire();
  156.             }
  157.             if (ks[Key.A])
  158.             {
  159.                 player.Move(-1, 0);
  160.             }
  161.             if (ks[Key.D])
  162.             {
  163.                 player.Move(1, 0);
  164.             }
  165.             if (ks[Key.W])
  166.             {
  167.                 player.Move(0, -1);   
  168.             }
  169.             if (ks[Key.S])
  170.             {
  171.                 player.Move(0, 1);
  172.             }
  173.             RenderGame();
  174.         }
  175.         
  176.         public void RenderGame()
  177.         {
  178.             d3dev.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0);
  179.    
  180.             d3dev.BeginScene();
  181.                 sprite.Begin(SpriteFlags.AlphaBlend);
  182.                     player.DrawSprite(sprite);
  183.                 sprite.End();
  184.             d3dev.EndScene();
  185.             d3dev.Present();

  186.         }

  187.         public bool InitGame()
  188.         {
  189.             if (!InitD3D())
  190.             {
  191.                 return false;
  192.             }

  193.             if (!InitKeyboard())
  194.             {
  195.                 return false;
  196.             }

  197.             sprite = new Sprite(d3dev);
  198.             player = new Actor(d3dev);
  199.             return true;
  200.         }

  201.         static void Main()
  202.         {
  203.             using (Game MainForm = new Game())
  204.             {
  205.                 if (!MainForm.InitGame())
  206.                 {

  207.                     MessageBox.Show("Failed to initialize D3D: " + DirectXException.GetDirectXErrorString(MainForm.errorNo));
  208.                     return;
  209.                 }
  210.                 MainForm.Show();

  211.                 while (MainForm.Created)
  212.                 {
  213.                     MainForm.UpdateGame();
  214.                     Application.DoEvents();
  215.                 }
  216.             }
  217.         }
  218.     }
  219. }
复制代码
回复

使用道具 举报

 楼主| 发表于 26-5-2008 09:19 PM | 显示全部楼层
这几天思考了一番,决定把 Actor 这个 struct 改为一切可以移动,会发生碰撞以及会在画面上绘出图像的物件的 Base class 目前在测试着,等确定没有问题就会把 source code 贴在这里。
回复

使用道具 举报

 楼主| 发表于 10-6-2008 11:31 AM | 显示全部楼层
这个Project将无限期暂停更新。(也就是说,可能永远也不会更新了)
回复

使用道具 举报

 楼主| 发表于 10-6-2008 11:34 AM | 显示全部楼层
是我写得太复杂吗?曲高和寡,没人懂得欣赏?冷冷清清的,怪不得各大论坛都如此痛恨潜水员,加上这里的人气实在很低。。。

这个Project将无限期暂停更新。(也就是说,可能永远也不会更新了)

以后就只做些小打小闹的小project好了。
回复

使用道具 举报


ADVERTISEMENT

发表于 15-6-2008 07:33 PM | 显示全部楼层
慢慢来吧.。。我的贴也虽然有时会5分钟热度,不过我不会轻意放弃的
回复

使用道具 举报

发表于 12-9-2008 12:50 AM | 显示全部楼层
我顶顶顶。。。

平时游戏光碟里的DirectX 9.0和DirectX 9.0 SDK一样吗??还是SDK版的另外安装?
回复

使用道具 举报

 楼主| 发表于 12-9-2008 09:38 AM | 显示全部楼层
游戏光碟里附送的是 run time version,不是 SDK,要获得 SDK 可以去 Microsoft 的网站下载。目前最新的应该是 August 2008 版本,我还在使用 March 2008 版本,因为新版的更新多数都是 DirectX 10 相关的,与我无关
回复

使用道具 举报

发表于 22-9-2008 12:23 AM | 显示全部楼层
现在在学习这个,C# + Managed DIrectX 制作 2D 游戏

一步步跟着做括弧有点乱,copy & paste 又跑不起。。。

现在,在 class Game:Form{}里面,在顶端加入以下的object/variable declaration:


在 class Game:Form{在这里吗??}

还是在这里??
在 class Game:Form{}

抱歉哦。。麻烦了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

 

ADVERTISEMENT



ADVERTISEMENT



ADVERTISEMENT

ADVERTISEMENT


版权所有 © 1996-2023 Cari Internet Sdn Bhd (483575-W)|IPSERVERONE 提供云主机|广告刊登|关于我们|私隐权|免控|投诉|联络|脸书|佳礼资讯网

GMT+8, 20-4-2024 04:42 AM , Processed in 0.085305 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表