频道栏目
读书频道 > 软件开发 > C# > 精通C#游戏编程
8.3.1 圆
2012-08-01 16:33:09     我来说两句
收藏   我要投稿

本文所属图书 > 精通C#游戏编程

本书通过引导读者创建一个基本的游戏,展示了如何使用c#和OpenGL一步步地开发出简单、整洁而可靠的代码。C#是一种高级编程语言,而OpenGL是业界显示图形最常用的方法。本书概述了创建优秀游戏项目时采用的方法和...  立即去当当网订购

圆通过位置和弧度定义。相交以图形化方式显示最容易理解。接下来就创建一个游戏状态CircleIntersectionState,使其成为默认加载的状态。

class CircleIntersectionState : IGameObject

{

public CircleIntersectionState()

{

Gl.glLineWidth(3);

Gl.glDisable(Gl.GL_TEXTURE_2D);

}

#region IGameObject Members

 

public void Update(double elapsedTime)

{

}

 

public void Render()

{

}

#endregion

}

现在状态只是准备好OpenGL,使其可以画线。接下来需要创建Circle类。

public class Circle

{

Vector Position { get; set; }

double Radius { get; set; }

 

public Circle()

{

Position = Vector.Zero;

Radius = 1;

}

 

public Circle(Vector position, double radius)

{

Position = position;

Radius = radius;

}

 

public void Draw()

{

// Determines how round the circle will appear.

int vertexAmount = 10;

double twoPI = 2.0 * Math.PI;

 

// A line loop connects all the vertices with lines

// The last vertex is connected to the first vertex

// to make a loop.

Gl.glBegin(Gl.GL_LINE_LOOP);

{

for (int i = 0; i <= vertexAmount; i++)

{

double xPos = Position.X + Radius * Math.Cos(i * twoPI /

vertexAmount);

double yPos = Position.Y + Radius * Math.Sin(i * twoPI /

vertexAmount);

Gl.glVertex2d(xPos, yPos);

}

}

Gl.glEnd();

}

}

默认情况下,在原点位置定义一个圆,其半径为1个单位。现在还没有编写绘制圆的代码。绘制圆时,将使用OpenGL的立即模式,即只绘制圆的轮廓。正弦和余弦函数用于确定在什么位置绘制组成圆周的各个顶点。

为了在CircleIntersectionState内测试绘图函数,应在类中添加一个成员_circle。

Circle _circle = new Circle(Vector.Zero, 200);

现在以原点为圆心、创建一个半径为200的圆。为了看到圆,需要修改渲染方法。

public void Render()

{

_circle.Draw();

}


 \


圆通过使用10个顶点绘制而成,所以看上去不是十分平滑。为了增加圆的平滑度,应增加Circle类的Draw方法中使用的顶点数。

为了演示相交性,最好能够为圆上色。使用白色的圆表示没有相交的圆,使用红色的圆表示圆与某个东西相交。实现这种功能很简单。在Circle类中,修改代码,添加一个在Draw函数中使用的颜色成员。

Color _color = new Color(1, 1, 1, 1);

public Color Color

{

get { return _color; }

set { _color = value; }

}

 

public void Draw()

{

Gl.glColor3f(_color.Red, _color.Green, _color.Blue);

默认情况下,所有的圆都将被渲染成白色,但是颜色可以随时改变。

介绍向量的部分已经解释了如何进行圆与点的相交性测试,方法是:计算点与圆心的距离,如果这个距离大于圆的半径,那么点位于圆之外。为了以图形化的方式进行测试,可以把鼠标指针作为一个点。

获得鼠标指针位置的操作稍微有点棘手,因为这涉及了不同的坐标系。OpenGL原点位于窗体的中心,但是光标的位置使用不同的坐标系确定,它的原点是窗体的左上角。也就是说,OpenGL认为窗体的中心是位置(0,0),但光标认为窗体的左上角才是[0,0]。图8-19显示了3个不同的坐标系。窗体的坐标原点标记为a,控件的坐标原点标记为b,OpenGL的坐标原点标记为c。为了将鼠标指针从窗体坐标系转换为OpenGL坐标系,需要向窗体中再添加一些代码。

 


\

首先需要一个简单的Input类来记录鼠标输入。

public class Input

{

public Point MousePosition { get; set; }

}

Input类将在窗体中初始化和更新。想知道鼠标位置的GameStates需要把Input对象放到自己的构造函数中。现在在窗体类中添加一个Input对象。

public partial class Form1 : Form

{

Input _input = new Input();

在窗体中需要创建一个新函数来更新输入类,该函数将在每一帧中调用。

private void UpdateInput()

{

System.Drawing.Point mousePos = Cursor.Position;

mousePos = _openGLControl.PointToClient(mousePos);

 

// Now use our point definition,

Point adjustedMousePoint = new Point();

adjustedMousePoint.X = (float)mousePos.X - ((float)ClientSize.Width

/ 2);

adjustedMousePoint.Y = ((float)ClientSize.Height / 2)-(float)mouse-

Pos.Y;

_input.MousePosition = adjustedMousePoint;

}

 

private void GameLoop(double elapsedTime)

{

UpdateInput();

UpdateInput使用PointToClient函数将光标的位置从窗体的坐标系转换到控件的坐标系。然后将基于OpenGL控件的中心,把光标位置转换到OpenGL坐标系中。这是将控件的X坐标和Y坐标减半实现的。现在,最终的坐标正确地将光标的位置从窗体坐标映射到OpenGL坐标。如果把光标放到OpenGL控件的中心,Input类将报告位置(0,0)。

在结束对窗体代码的讨论之前,还需要编写最后一项功能:必须把新的输入对象添加到圆的状态的构造函数中。

_system.AddState("circle_state", new CircleIntersectionState(_input));

还必须修改状态的构造函数。

Input _input;

public CircleIntersectionState(Input input)

{

_input = input;

将输入传递给状态以后,就可以使用光标的位置了。有必要确认代码都在正确工作。最简单的方法是,使用OpenGL在光标所在的位置绘点。

public void Render()

{

Gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);

_circle.Draw();

 

// Draw the mouse cursor as a point

Gl.glPointSize(5);

Gl.glBegin(Gl.GL_POINTS);

{

Gl.glVertex2f(_input.MousePosition.X,

_input.MousePosition.Y);

}

Gl.glEnd();

}

运行程序,光标总是会带着一个小方块。注意代码中添加了一个glClear命令。试着删除glClear命令,看看会发生什么事情。

现在鼠标指针已经可以工作,接下来返回到相交性代码。状态的更新循环将执行相交性测试。

public void Update(double elapsedTime)

{

if (_circle.Intersects(_input.MousePosition))

{

_circle.Color = new Color(1, 0, 0, 1);

}

else

{

// If the circle's not intersected turn it back to white.

_circle.Color = new Color(1, 1, 1, 1);

}

}

这是intersect函数的用法,接下来就实际编写该函数。这个测试需要使用大量向量操作,所以把指针对象转换成了一个向量。

public bool Intersects(Point point)

{

// Change point to a vector

Vector vPoint = new Vector(point.X, point.Y, 0);

Vector vFromCircleToPoint = Position - vPoint;

double distance = vFromCircleToPoint.Length();

 

if (distance > Radius)

{

return false;

}

return true;

}

运行程序,观察光标移入和移出圆时会发生什么情况。


您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:8.3 二维相交
下一篇:8.3.2 矩形
相关文章
图文推荐
排行
热门
最新书评
特别推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站