【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏<一>

呃,小儿科拿出来讨论一下。

巨注意:不是让大家去写外挂哦!纯属技术讨论。

先写一部分,测试是用GDI+写的,非常的简陋,而且整体只是一个雏形,抛砖引玉。

【一、物理引擎】

      所谓物理引擎,是通过为刚体赋予真实的物理属性的方式来计算它们的运动、旋转、碰撞等等的结果。也许你曾经编写过台球游戏,使用了大量的类似于碰撞检测,线相交和折返等等数学方法来解决问题,但那不是对真实世界的物理模拟,虽然可以使你的游戏看起来比较真实,但当游戏需要比较复杂的物体碰撞、滚动、滑动或者弹跳的时候(比如赛车类游戏或者保龄球游戏),通过编程的方法就比较困难了。而物理引擎则使用动量、扭矩等用高等数学手段来模拟真实物体,这将得到更真实的效果且使我们的编码更加容易。当然好的物理引擎允许有复杂的机械装置,像球形关节、轮子、气缸或者铰链。有些也支持非刚性体的物理属性,比如流体。

著名的物理引擎有:

Lagoa Multiphysics

Physx

Bullet

Havok

等等,它们多提供3D特性,用于在三维空间内来模拟物理运动——就像星际2、暗黑3使用的就是Havok。这些物理引擎当然可以应用到2D游戏当中,但它们的运算量将会大于2D引擎。很多物理引擎提供了图形界面功能,AI功能等诸多游戏要素,而且非常出色!但我们这里还是从比较简单的BOX2D入手,说它简单是它只负责计算物理运动(当然它也非常强大——除了不支持流体等)进而只提供了很少的一些接口,这有利于我们专注于物理引擎的使用。

出处:http://www.cnblogs.com/zcsor/

【二、BOX2D】

Box2D 是一个用于游戏的 2D 刚体仿真库。程序员可以在他们的游戏里使用它,它可以使物体的运动更加可信,让世界看起来更具交互性。从游戏的视角来看,物理引擎就是一个程序性动画(proceduralanimation)的系统,而不是由动画师去移动你的物体。你可以让牛顿来做导演。Box2D 是用可移植的 C++ 来写成的。引擎中定义的大部分类型都有 b2 前缀,希望这能消除它和游戏引擎之间的名字冲突。这就是BOX2D的概况。在学习如何使用时,我们先认识几个必要概念和它们存在的意义:

A、我想,质量,力,扭矩和冲量大家都非常清楚了,呃,如果不清楚那可以去百科恶补一下……

B、刚体:即说这个物体会在碰撞、挤压等力的作用后不变形。你应该注意我这个描述。(当然如果你愿意,可以告诉BOX2D改变它的任何属性)

C、形状:这决定了物体的外观以及碰撞等发生的位置,当然,还有摩擦的大小等

D、自由度:这个概念也许比较深奥,但在这里,我们只需要知道,2D物理引擎只模拟物体在一个平面上的运动——即你的游戏将是一个平面游戏,即使你用一些手段将地面和墙壁以及天空分开。。。其实不必在意,这种伎俩已经很少有游戏在用了,而且我相信当XNA向VB.NET微笑时,那些手段会被赶出你的脑袋。

E、世界:我们应该把所有物体限定在一个范围内——当物体跑出去了,引擎会抛出一个错误并停止对该物体进行演算,所以,我们的世界通常有足够大……

F、其他:当然指关节,齿轮等,这些与我们入门毫无关系。甚至在我的代码里也采用了一些卑劣的手段避开使用回调方式来处理物体的接触——这将使代码更“入门”,而且也足够应付这么简单的情况

【三、创建一个世界】

首先,确保你引用了BOX2D引擎。如果没有可以在其网站下载:http://www.box2d.org/

接下来我们创建一个世界,这是使用BOX2D引擎的第一步:

        '世界外边框
        Dim Wordaabb As Box2DX.Collision.AABB
        Wordaabb.LowerBound.Set(-10000.0F, -10000.0F)
        Wordaabb.UpperBound.Set(10000.0F, 10000.0F)
        '创建世界,第二个参数是重力,第三个是是否允许引擎休眠
        world = New Box2DX.Dynamics.World(Wordaabb, g, False)

这样,就创建完成了,非常简单吧!

【四、创建一个物体】

在BOX2D中,物体是这样创建的:

1、首先有一个“物体”(之所以这样叫,是因为到你附加形状并计算质量之前,它应该只是一个“抽象”的处于意识中的物体)被创建,但是他没有形态

2、指定物体的一些信息:位置,空气阻尼等

3、创建一个形态并设置由形态先关的信息:体积、密度、摩擦系数等

出处:http://www.cnblogs.com/zcsor/

4、为物体附加形态,让引擎计算其质量

可能这不是我们所习惯的,但你确实应该这样做:先设置形态,然后设置密度,因为决定物体运动状态的并不只是质量,形态将起到决定性作用!
        '创建动态物体,它的质量一定要大于0
        Dim bodyDef As New Box2DX.Dynamics.BodyDef

        '物体的位置
        bodyDef.Position.Set(X,Y)

        '空气的阻尼
        bodyDef.LinearDamping = Damping

        '实际物体
        Dim Body As Box2DX.Dynamics.Body

        '在世界中创建物体
        Body = world.CreateBody(bodyDef)
        '为物体附加一个多边形
        Dim shapeDef As New Box2DX.Collision.CircleDef
        shapeDef.IsSensor = IsSensor  '可否“休眠”即物体不动时引擎是否可以不计算它。(可能听起来有点别扭)
        shapeDef.Radius = R   '设置体积为1,以使得质量计算结果为1
        shapeDef.Density = Density    '密度
        'shapeDef.Friction = 1   '摩擦系数
        Dim shape = Body.CreateShape(shapeDef) '附加到物体
        Body.SetMassFromShapes()   '根据形状计算质量
至此,我们创建了一个动态物体。

 

 

【五、物体的运动】

好,我们先考虑一下,影响我们的“炮弹”运动轨迹的因素都有哪些:

1、重力

2、发射角度

3、发射力度

4、空气阻尼

5、风力

6、发射点(这在创建动态物体时已经被指定了,当然你可以告诉引擎来修改它的属性来使它停下并“瞬移”到你想要的位置重新开始运动。但我没有这样做——出于编码的原因当它无用时,我销毁它,下次计算时创建一个新物体,这样做效率并不很低)所以我们不关心它。

好,我们一个一个解决这些问题:

1、重力——这个属性是属于世界的,一般我们定义重力是向下的一个向量(BOX2D提供了用于内置计算的向量对象)

Dim g As New Box2DX.Common.Vec2(0.0F, 17.27F)               '重力

2、3、发射角度和力度——这将是瞬间完成的,不要指望去模拟一个在炮筒中的爆炸,那是得不偿失的——我们直接用一个向量作用于物体质心即可:

Body.ApplyImpulse(New Box2DX.Common.Vec2( Math.Cos(Angle) * Power , -Math.Sin(Angle) * Power), Body.GetPosition)

这个语句可能稍微复杂一些,实际上有两个参数,第一个就是冲量,第二个是物体当前位置。

第一个参数只是用了三角形的基本知识,将发射角度和力度进行换算,得到X,Y两个方向上的力——即得到一个向量^ ^。

4、空气阻尼——一个属于物体的性质:这也灰常的简单,只需要告诉BOX2D一个数值,它就会在迭代器模拟物理运动的计算过程中应用它。

bodyDef.LinearDamping = Damping

5、风力——这是一个BOX2D所没有提供的性质,换句话说,BOX2D的世界里没有风……果然是灰常的风和日丽……那怎么办呢?呃……

思考中……

思考中……

其实物理引擎无非是在一定的时刻(后面将提到步长)近似的求得物体的位置及速度(线速度和角速度),那么我们可以在每次计算时,都作用一个风力给物体。这是我的解决方案,当然,你也可以改变重力的大小和方向来达到目的(将风力和重力的合力作为重力),也许你还有更好的办法……

好了,这个风力代码我是这样写的:

 '添加位置到返回数组

        Dim ret(MaxStep) As Box2DX.Common.Vec2
        For i As Integer = 0 To MaxStep
            Body.ApplyForce(f, Body.GetPosition)    '应用风力
            world.Step(timeStep, MaxStep, 1)         '步进计算,第一个参数是步长(多久计算一次),第二个参数是计算的最多步数,第三个,呃是迭代数(每次计算时用迭代器的次数)
            ret(i) = New Box2DX.Common.Vec2(Body.GetPosition.X, Body.GetPosition.Y)               '当前步位置
            '检测进入
            'Dim s(0) As Box2DX.Collision.Shape

‘出处:http://www.cnblogs.com/zcsor/
            'If RsEvnt = False AndAlso world.Query(mAABB, s, 1) = 1 Then
            '    RsX = Body.GetPosition.X * 10
             '   RsY = Body.GetPosition.Y * 10
             '   RsEvnt = True
            'End If
        Next

为了看起来更清晰,我仅保留了记录当前位置和应用风力的代码——注释掉的是检测是否击中目标的代码。

至此,我们已经可以得到一个物体的运动轨迹,也许——你应该在GDI+上绘制一下他们了。

 

【六、冲突检测】

BOX2D提供了AABB检测和其他的冲突检测方式。我们这里简要的提一下AABB,如果你感兴趣,完全可以使用“接触监听器”或者“传感器”来完成你的代码。

创建一个AABB检测和使用它将非常简单:只需要设置AABB的两个坐标点——像创建世界外边框那样,指定左上角和右下角。
        mAABB.LowerBound.Set(X1, Y1)
        mAABB.UpperBound.Set(X2, Y2)

而检测代码已经在上面的代码中了——还记得吗,我把他们注释掉了。

【后记】

上面讲到的类,代码如下:

 

代码
Public   Class  Box2DEngine
    
Dim  world  As  Box2DX.Dynamics.World
    
Dim  g  As   New  Box2DX.Common.Vec2( 0 .0F,  17 .27F)                ' 重力
     Dim  Damping  As   Single   =   0 .1F                                 ' 空气阻尼
     Dim  WapOffset  As  PointF  =   New  PointF( 2 .5F,  - 2 .5F)            ' 相对于人物中心的武器的偏移量
     Dim  RevisePower  As   Single   =   4 .0F                             ' 力度
     Dim  ReviseWind  As   Single   =   2 .474F                            ' 风速
     Dim  Density  As   Single   =   5.0929579415893746                    ' 密度
     Dim  timeStep  As   Single   =   1   /   25                               ' 时间步数——游戏每帧时间
     Dim  mAABB  As   New  Box2DX.Collision.AABB                       ' 范围检测,这里用的不是冲突而是范围内是否有物体
     Public   Event  InAABB( ByVal  power  As   Single ByVal  x  As   Single ByVal  y  As   Single ByVal  vs()  As  Box2DX.Common.Vec2)
    
Public   Event  NotInAABB( ByVal  power  As   Single ByVal  x  As   Single ByVal  y  As   Single ByVal  vs()  As  Box2DX.Common.Vec2)

    
Public   Enum  ForRight  As   Integer
        Yes 
=   1
        No 
=   - 1
    
End Enum

    
Sub   New ()
        
' 世界外边框
         Dim  Wordaabb  As  Box2DX.Collision.AABB
        Wordaabb.LowerBound.Set(
- 10000 .0F,  - 10000 .0F)
        Wordaabb.UpperBound.Set(
10000 .0F,  10000 .0F)
’出处:http://www.cnblogs.com/zcsor/
        
' 允许引擎休眠
         Dim  dosleep  As   Boolean   =   False   '  True
         ' 创建世界
        world  =   New  Box2DX.Dynamics.World(Wordaabb, g, dosleep)
    
End Sub

    
Sub  SetAABB( ByVal  p  As  PointF,  ByVal  mSize  As  SizeF)
        mAABB.LowerBound.Set(p.X 
/   10   -  mSize.Width, p.Y  /   10   -  mSize.Height)
        mAABB.UpperBound.Set(p.X 
/   10   +  mSize.Width, p.Y  /   10   +  mSize.Height)
    
End Sub

    
'''   <summary>
    
'''  获取指定状态下的关键点
    
'''   </summary>
    
'''   <param name="PlayerPoint"> 玩家位置(玩家中心位置的屏幕坐标) </param>
    
'''   <param name="ForRight"> 玩家是否朝向右面 </param>
    
'''   <param name="Power"> 射击力度 </param>
    
'''   <param name="Angle"> 射击角度(无左右方向,有上下方向) </param>
    
'''   <param name="Wind"> 风力及方向,向右为正,向左为负 </param>
    
'''   <param name="MaxStep"> 最大计算步数,每一秒计算25次 </param>
    
'''   <returns> 从当前位置开始模拟运动时,每一步的坐标 </returns>
    
'''   <remarks></remarks>
     Public   Function  GetPath( ByVal  PlayerPoint  As  PointF,  ByVal  ForRight  As  ForRight,  ByVal  Power  As   Single ByVal  Angle  As   Double ByVal  Wind  As   Single ByVal  MaxStep  As   Single As  Box2DX.Common.Vec2()
        
Dim  RsEvnt  As   Boolean
        
Dim  RsX, RsY  As   Single
        
Dim  ret(MaxStep)  As  Box2DX.Common.Vec2
        
' 创建一个动态物体
         Dim  Body  As  Box2DX.Dynamics.Body  =  CreateBody(PlayerPoint, ForRight,  0 .5F,  False , Angle)
        
' 发射——对其质心应用一个冲力
        Body.ApplyImpulse( New  Box2DX.Common.Vec2( CInt (ForRight)  *  Math.Cos(Angle)  *  Power  *  RevisePower,  - Math.Sin(Angle)  *  Power  *  RevisePower), Body.GetPosition)
        
' 一个持久作用力——风力
         Dim  f  As  Box2DX.Common.Vec2  =   New  Box2DX.Common.Vec2(Wind  *  ReviseWind,  0 )
        
' 添加位置到返回数组
         For  i  As   Integer   =   0   To  MaxStep
            Body.ApplyForce(f, Body.GetPosition)    
' 应用风力
            world.Step(timeStep, MaxStep,  1 )         ' 步进计算
            ret(i)  =   New  Box2DX.Common.Vec2(Body.GetPosition.X, Body.GetPosition.Y)                ' 当前步位置
             ' 检测进入
             Dim  s( 0 As  Box2DX.Collision.Shape
            
If  RsEvnt  =   False   AndAlso  world.Query(mAABB, s,  1 =   1   Then
                RsX 
=  Body.GetPosition.X  *   10
                RsY 
=  Body.GetPosition.Y  *   10
                RsEvnt 
=   True
            
End   If
        
Next
        
' 销毁这次用的BODY,下次将重新创建
        world.DestroyBody(Body)
        Body.Dispose()
        Body 
=   Nothing
        
If  RsEvnt  Then
            
RaiseEvent  InAABB(Power, RsX, RsY, ret)
        
Else
            
RaiseEvent  NotInAABB(Power, RsX, RsY, ret)
        
End   If
        
Return  ret
    
End Function

    
Private   Function  RotateV2( ByVal  p  As  PointF,  ByVal  a  As   Double As  PointF
        
Dim  ret  As   New  PointF
        
Dim  b  As   Double   =   - a
        ret.X 
=  p.X  *  Math.Cos(b)  -  p.Y  *  Math.Sin(b)
        ret.Y 
=  p.X  *  Math.Sin(b)  +  p.Y  *  Math.Cos(b)
        Debug.Print(b)
        Debug.Print(ret.ToString)
        
Return  ret
    
End Function

    
'''   <summary>
    
'''  根据玩家位置和是否向右,来创建一个炮弹,这个炮弹的具体位置和发射者位置及角度相关。
    
'''   </summary>
    
'''   <param name="PlayerPoint"> 玩家位置 </param>
    
'''   <param name="ForRight"> 是否向右 </param>
    
'''   <param name="R"> 半径 </param>
    
'''   <param name="IsSensor"> 是否是感应器 </param>
    
'''   <param name="Angle"> 发射角度 </param>
    
'''   <returns></returns>
    
'''   <remarks></remarks>
     Private   Function  CreateBody( ByVal  PlayerPoint  As  PointF,  ByVal  ForRight  As  ForRight,  ByVal  R  As   Single ByVal  IsSensor  As   Boolean ByVal  Angle  As   Double As  Box2DX.Dynamics.Body
        
' Debug.Print(CInt(ForRight))
         ' 创建动态物体,它的质量一定要大于0
         Dim  bodyDef  As   New  Box2DX.Dynamics.BodyDef
        WapOffset 
=  RotateV2( New  PointF( 2.5 0 ), Angle)
        bodyDef.Position.Set((PlayerPoint.X 
/   10   +   CInt (ForRight)  *  WapOffset.X), (PlayerPoint.Y  /   10   +  WapOffset.Y))
        bodyDef.LinearDamping 
=  Damping
        
Dim  Body  As  Box2DX.Dynamics.Body
        Body 
=  world.CreateBody(bodyDef)
        
' 为物体附加一个多边形
         Dim  shapeDef  As   New  Box2DX.Collision.CircleDef
        shapeDef.IsSensor 
=  IsSensor
        shapeDef.Radius 
=  R    ' 设置体积为1,以使得质量计算结果为1
        shapeDef.Density  =  Density     ' 密度
         ' shapeDef.Friction = 1   '摩擦系数
         Dim  shape  =  Body.CreateShape(shapeDef)  ' 附加到物体
        Body.SetMassFromShapes()    ' 根据形状计算质量
         Return  Body
    
End Function

    
Protected   Overrides   Sub  Finalize()
        world.Dispose()
        
MyBase .Finalize()
    
End Sub
End Class

 

而我所用的测试代码如下:

 

代码


Public   Class  Form1
    
Dim  gr  As  Graphics       ' 窗体的画布
     Dim  CompassRect  As  Rectangle     ' 罗盘
     Dim  po  As  Point      ' 罗盘中心
     Dim  p1  As  Point      ' 指针终点
     Dim  powerRect  As  Rectangle   ' 力度框
     Dim  mb  As  Point  ' 目标位置
     Dim  wind  As   Single    ' 风力
     Dim  ang  As   Integer    ' 角度
     Dim  Userpower  As   Single   ' 力度*5
     Dim  mFont  As  Font    ' 字体
     Dim   WithEvents  eg  As   New  Box2DEngine     ' 封装引擎
     Dim  v2s()  As  Box2DX.Common.Vec2      ' 路径点
     Dim  img  As  Bitmap        ' 背景图
     Dim  grp  As  Graphics      ' 背景图或最终图的画布
     Dim  pnt  As  Bitmap        ' 最终图

    
Private   Sub  Form1_KeyPress( ByVal  sender  As   Object ByVal  e  As  System.Windows.Forms.KeyPressEventArgs)  Handles   Me .KeyPress
        
Select   Case  e.KeyChar
            
Case   "   "
                
If  My.Computer.Keyboard.ShiftKeyDown  Then
                    
If  Userpower  >   0   Then  Userpower  -=   2.5
                
Else
                    
If  Userpower  <   500   Then  Userpower  +=   2.5
                
End   If
            
Case   " w " " W "
                
If  ang  >   - 90   Then  ang  -=   1
            
Case   " s " " S "
                
If  ang  <   90   Then  ang  +=   1
            
Case   " r " " R "
                
Randomize ()
                wind 
=   CInt ( Int (( 100   *   Rnd ())))  /   10   -   5
                mb 
=   New  Point( 800   *   Rnd ()  +   180 500   *   Rnd ())
                eg.SetAABB(
New  PointF(mb.X, mb.Y),  New  Size( 20 20 ))
                Userpower 
=   0
        
End   Select
        Form1_Paint(
Me New  PaintEventArgs(gr,  Me .ClientRectangle))
    
End Sub

    
Private   Sub  Form1_KeyUp( ByVal  sender  As   Object ByVal  e  As  System.Windows.Forms.KeyEventArgs)  Handles   Me .KeyUp
        
Select   Case  e.KeyData
            
Case  Keys.Space, Keys.Shift  Or  Keys.Space, Keys.ShiftKey  Or  Keys.Space, Keys.W, Keys.S
                v2s 
=  eg.GetPath( New  PointF(po.X, po.Y), Box2DEngine.ForRight.Yes, Userpower  /   5 - ang  *  Math.PI  /   180 , wind,  300 )
        
End   Select
    
End Sub

    
Private   Sub  Form1_Load( ByVal  sender  As  System.Object,  ByVal  e  As  System.EventArgs)  Handles   MyBase .Load
        img 
=   New  Bitmap( 1000 600 )
        grp 
=  Graphics.FromImage(img)
        
Dim  alppen  As  Pen  =   New  Pen(Color.FromArgb( & H40FFFFFF))
        grp.DrawString(
" 按W增加角度 "   &  vbCrLf  &   " 按S减少角度 "   &  vbCrLf  &   " 按空格增加力度 "   &  vbCrLf  &   " 按SHIFT+空格减少力度 "   &  vbCrLf  &   " 按R重置 " New  Font( " 宋体 " 18 ), Brushes.DarkCyan,  0 0 )
        
For  x  As   Integer   =   0   To   1000   Step   100
            grp.DrawLine(Pens.White, x, 
595 , x,  600 )
            grp.DrawLine(alppen, x, 
0 , x,  595 )
            grp.DrawString(x 
/   100 , Font, Brushes.White, x,  590 )
        
Next
        
For  y  As   Integer   =   0   To   600   Step   60
            grp.DrawLine(alppen, 
0 , y,  1000 , y)
        
Next
        pnt 
=   New  Bitmap( 1000 600 )
        grp.Dispose()
        grp 
=  Graphics.FromImage(pnt)
        gr 
=   Me .CreateGraphics
        CompassRect 
=   New  Rectangle( 0 300 100 100 )
        po 
=   New  Point(CompassRect.X  +  CompassRect.Width  /   2 , CompassRect.Y  +  CompassRect.Height  /   2 )
        p1 
=   New  Point(CompassRect.X  +  CompassRect.Width  /   2   +   35 , CompassRect.Y  +  CompassRect.Height  /   2 )
        powerRect 
=   New  Rectangle( 150 570 502 20 )
        mFont 
=   New  Font( " 宋体 " 24 , FontStyle.Bold)
    
End Sub

    
Private   Sub  Form1_Paint( ByVal  sender  As   Object ByVal  e  As  System.Windows.Forms.PaintEventArgs)  Handles   Me .Paint
        grp.Clear(Color.DarkGreen)
        grp.DrawImage(img, PointF.Empty)
        
Dim  offset  As  Point  =  RotateV2(p1  -  po,  - ang)  +  po
        grp.DrawLine(Pens.Blue, po, offset)

        grp.DrawString(
- ang, mFont, Brushes.Blue, po.X  -   15 , po.Y  +   10 )
        grp.FillPie(Brushes.White, 
New  Rectangle(po.X  -   10 , po.Y  -   10 20 20 ),  0 360 )
        grp.DrawRectangle(Pens.White, powerRect)
        grp.FillRectangle(Brushes.Wheat, 
New  Rectangle(powerRect.X  +   1 , powerRect.Y  +   1 , Userpower,  19 ))
        grp.DrawString(Userpower 
/   5 , mFont, Brushes.Blue, powerRect.X, powerRect.Y  -   35 )
        grp.DrawString(Math.Abs(wind), mFont, Brushes.Blue, 
490 10 )
        grp.DrawString(
IIf (wind  <   0 " " " " ), mFont, Brushes.Blue,  490 30 )
        
If  mb.X  >   0   AndAlso  mb.Y  >   0   Then  grp.FillPie(Brushes.Black,  New  Rectangle(mb.X  -   10 , mb.Y  -   10 20 20 ),  0 360 )
        
If  v2s  IsNot   Nothing   Then
            
For   Each  v2  As  Box2DX.Common.Vec2  In  v2s
                grp.DrawArc(Pens.White, 
CSng (v2.X  *   10 .0F  -   0.5 ),  CSng (v2.Y  *   10   -   0.5 ),  1 .0F,  1 .0F,  0 .0F,  360 .0F)
            
Next
        
End   If
        v2s 
=   Nothing
        gr.DrawImage(pnt, PointF.Empty)
    
End Sub

    
Private   Function  RotateV2( ByVal  p  As  Point,  ByVal  a  As   Integer As  Point
        
Dim  ret  As   New  Point
        
Dim  b  As   Double   =   - *  Math.PI  /   180
        ret.X 
=  p.X  *  Math.Cos(b)  -  p.Y  *  Math.Sin(b)
        ret.Y 
=  p.X  *  Math.Sin(b)  +  p.Y  *  Math.Cos(b)
        
Return  ret
    
End Function

    
Private   Sub  eg_InAABB( ByVal  power  As   Single ByVal  x  As   Single ByVal  y  As   Single ByVal  vs()  As  Box2DX.Common.Vec2)  Handles  eg.InAABB
        v2s 
=  vs
        Form1_Paint(
Me New  PaintEventArgs(gr,  Me .ClientRectangle))
    
End Sub

    
Private   Sub  eg_NotInAABB( ByVal  power  As   Single ByVal  x  As   Single ByVal  y  As   Single ByVal  vs()  As  Box2DX.Common.Vec2)  Handles  eg.NotInAABB
        v2s 
=  vs
        Form1_Paint(
Me New  PaintEventArgs(gr,  Me .ClientRectangle))
    
End Sub
End Class

 

好了,只是抛砖引玉,希望大家能够开发出自己的游戏,毕竟别人的游戏只是一种借鉴,学会思考才是最重要的。

PS:代码中使用了坐标缩放,这是因为物理引擎模拟运动时,只在一定范围内(例如十米以内)有较高的准确度,超出这个范围将会降低准确度。

PS:BOX2D是使用单精度浮点数来进行计算的——这不会对准确度影响较大。因为它使用了一些通用的公差。

原文:http://www.cnblogs.com/zcsor/

贴了这么多出处我也没办法。因为有些同学脸皮太薄了——将将比城墙厚一点点!

你可能感兴趣的:(游戏)