目錄
       第一步:创建world(世界)
    第二步:创建墙(边界)
        使用DebugDraw来呈现在Box2D世界发生了什么
首頁 資料庫 mysql教程 使用Box2D制作AS3游戏2.1a版本Hello World Box2D

使用Box2D制作AS3游戏2.1a版本Hello World Box2D

Jun 07, 2016 pm 03:30 PM
2.1a 使用 製作 遊戲 版本

想要制作一个像纸上怪物一样酷的基于物理学的flash游戏吗? 最好的方式就是使用一个叫做Box2D的很好的flash开源类库。现在有很多关于flash的物理引擎,但是Box2D就属于这些引擎中的战斗机。很多开发人员选择使用Box2D,并且现在Box2D有许多个语言版本(C,jav

        想要制作一个像纸上怪物一样酷的基于物理学的flash游戏吗? 最好的方式就是使用一个叫做Box2D的很好的flash开源类库。现在有很多关于flash的物理引擎,但是Box2D就属于这些引擎中的战斗机。很多开发人员选择使用Box2D,并且现在Box2D有许多个语言版本(C++,java,xna,iphone,android),这使得Box2D成为了一款炙手可热的开发引擎。

       但是这也意味着,大部分的教程使用的不是AS3.0的编程语言,或者使用的是过时的版本。

      本教程使用AS3.0,以及最新的Box2D——2.1a版本。

      在本教程中,将会运用Box2D创建一个由能够进行真实碰撞的对象组成的世界,让你在实践中学习取得经验。

     如果你是第一次接触Box2D,你可能会对其以直观的方式将创建一个物体分为几个步骤的方式感到不解。比如,如果你想创建一个方块状和一个球状图形,并让他们能够发生碰撞。你可能希望只需要一个Block类和Ball类,通过new就能创建方块状和一个球状图形,并将他们添加到你的Box2dWord.

      但是你错了,在Box2D中,如果你想创建一个方块,你需要进行以下几个步骤,现在不用去担忧它是否是没意义的,后面我们将给出案例源码。

      1.创建一个Shape(形状)——这是一个对象的几何部分。
      2.创建一个Body(刚体)定义——这是Box2D中的一个特殊对象类型,作为创建刚体的参数。
      3.告诉World(世界)创建一个body(刚体)——将你创建的body定义传给world(世界),让世界以它作为参数创建一个刚体。一个刚体在世界中是由多个形状构成的不可分割的对象,这些形状共享同一个质心,即刚体的质心。
      4.创建一个fixture(固定附着物,即形状与刚体的绑定物)——fixture是box2d中的一个新的对象类型,用于定义添加到刚体上的形状的属性

      Box2D有一个特殊的方式让你创建物体。而且你必须在正确的时间,按正确的顺序进行。它不需要你在了解其内部组织结构上浪费时间。原因有两方面:其一,它最初是用不同的语言编写的,它遵循这些语言的许多公约。其二,这些步骤使得Box2D的运行很有效率。

      要明白,Box2D和其它的Actionscript APIS是不同的。不要去反对它,去用它就行了。因为它对自己的规则非常自信,并且异常强大。

      好了,让我们来写一些代码。我们将要创建一个box2d世界,在里面建两个矩形刚体,并用box2d内置的调试渲染器将其画在屏幕上。下面是我们将要创建的整个类。现在只需要大致的看一下,后面我们将详细的对其进行讲解。

   

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	// Bring In Box2D
	import Box2D.Dynamics.*
	import Box2D.Collision.*
	import Box2D.Collision.Shapes.*
	import Box2D.Dynamics.Joints.*
	import Box2D.Dynamics.Contacts.*
	import Box2D.Common.Math.*
 
	/**
	 * ...
	 * @author Zach
	 */
	public class Main extends Sprite
	{
		private var world:b2World;
		private var timestep:Number;
		private var iterations:uint;
		private var pixelsPerMeter:Number = 30;
 
		public function Main():void
		{
 
			makeWorld();
			makeWalls();
			makeDebugDraw();
 
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
 
		}
 
		private function makeWorld():void
		{
			// Define the gravity vector
			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
			// Allow bodies to sleep
			var doSleep:Boolean = true;
			// Construct a world object
			world = new b2World(gravity, doSleep);
			world.SetWarmStarting(true);
			timestep = 1.0 / 30.0;
			iterations = 10;
 
		}
 
		private function makeWalls():void
		{
			// Note: I am assuming a stage size of 640x400;
			// These placements will put a row of boxes around an area that size.
 
			// We reuse the shape and Body Definitions.
			// Box2D creates a different body each time we call world.CreateBody(wallBd);
			var wall:b2PolygonShape= new b2PolygonShape();
			var wallBd:b2BodyDef = new b2BodyDef();
			var wallB:b2Body;
 
			// Left
			wallBd.position.Set( -95 / pixelsPerMeter, 400 / pixelsPerMeter / 2);
			wall.SetAsBox(100/pixelsPerMeter, 400/pixelsPerMeter/2);
			wallB = world.CreateBody(wallBd); // Box2D handles the creation of a new b2Body for us.
			wallB.CreateFixture2(wall);
			// Right
			wallBd.position.Set((640 + 95) / pixelsPerMeter, 400 / pixelsPerMeter / 2);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			// Top
			wallBd.position.Set(640 / pixelsPerMeter / 2, -95 / pixelsPerMeter);
			wall.SetAsBox(680/pixelsPerMeter/2, 100/pixelsPerMeter);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			// Bottom
			wallBd.position.Set(640 / pixelsPerMeter / 2, (400 + 95) / pixelsPerMeter);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
 
		}
 
		private function makeDebugDraw():void
		{
			// set debug draw
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			addChild(debugSprite);
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.3);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			world.SetDebugDraw(debugDraw);
		}
 
		private function init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			update()
		}
 
		private function update(e:Event = null):void
		{
			world.Step(timestep, iterations, iterations);
			world.ClearForces();
			// Render
			world.DrawDebugData();
		}
 
	}
 
}
登入後複製

        通览整个类,如果你看到6-11行,我们使用通配符*导入Box2d来引用所有类。对于本教程来说这种做法很好,但是在实际操作中,我通常只导入需要用到的类。

        教程中,我已经在构造函数中调用了三个函数,这三个函数的名称代表我们将要进行的三个步骤(27-29行).让我们详细的来看看每一个步骤:首先,创建世界。

       第一步:创建world(世界)

      在Box2D 2.1a版本中,创建世界要比以前的版本简单得多。如果你看过旧版本的例子,你应该知道,创建世界需要进行定义世界的大小等许多零零碎碎的操作。但是现在不用了。

     现在创建世界非常的直接了当。

  

private function makeWorld():void
		{
			// Define the gravity vector
			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
			// Allow bodies to sleep
			var doSleep:Boolean = true;
			// Construct a world object
			world = new b2World(gravity, doSleep);
			world.SetWarmStarting(true);
			timestep = 1.0 / 30.0;
			iterations = 10;
 
		}
登入後複製

第4行  我们定义了一个重力变量,为向量类型,世界中的所有对象都将被赋予这个重力向量。你可以通过设置向量为(0,-10)来创建反重力,或者设置向量为(0,0)来创建零重力,甚至是将X参数设为一个正数,Y参数设为O来创建不可思议的侧身重力。

第6行  决定是否让Box2D停止检测已经停止移动的物体的碰撞。设为True会降低CPU的消耗,但是你需要注意在某些情况下使其为flase.就个人而言,我还没遇到这样的情况。
第8行 创建世界!我们设置它的重力参数,是否休眠属性。
第9行 告诉世界,所有的刚体开始的时候都没有休眠。如果你设为flase,新建的刚体将不会立刻受到重力的影响直到你明确的将他们唤醒,或受到外力的作用。对于用Box2d制作像台球类型的游戏,因为其游戏开始的时候所有的球都是静止的,就可以将其设为flase.
第10行    Box2D在指定的时间内处理模拟对象的碰撞检测。timestep(步长)告诉Box2d两次碰撞检测应该间隔多久时间。保持这个数值较小是个好主意。

第11行 告诉Box2D在移动前要解决多少次复杂的碰撞。考虑这样一个情形,一次碰撞让一个刚体移进第三个刚体。现在他们发生了碰撞,并将一个刚体反弹回第一个刚体。由于物理模拟的实质,这些碰撞将没有止境。你使用iterations(迭代次数)告诉box2D“好了,已经够近了——向前移动",如果你将iterations设得小,你的碰撞模拟将会包含更多的错误和奇怪的行为,但是会更快。如果你将其值设得较大,将会更加精确,但是会降低整个程序的性能。除非你遇到问题,不然就将其值都设为10.

现在进行下一步——添加对象到我们的世界。

    第二步:创建墙(边界)

      现在我们有了一个空的Box2D世界。现在我们将添加一些能发生碰撞的刚体到里面。值得注意的是,Box2D中所有的类都是以”b2“为前缀开始的。这是一个非常有用的方式,通过这个方式,Box2D确保你不会创建和其同名的类。于是你创建一个英雄,英雄有一个身体——你依然可以为他创建一个b2Body,而不用担心覆盖类名。

      下面是创建边界墙的代码:

private function makeWalls():void
		{
			// Note: I am assuming a stage size of 640x400;
			// These placements will put a row of boxes around an area that size.
 
			// We reuse the shape and Body Definitions.
			// Box2D creates a different body each time we call world.CreateBody(wallBd);
			var wall:b2PolygonShape= new b2PolygonShape();
			var wallBd:b2BodyDef = new b2BodyDef();
			var wallB:b2Body;
 
			// Left
			wallBd.position.Set( -95 / pixelsPerMeter, 400 / pixelsPerMeter / 2);
			wall.SetAsBox(100/pixelsPerMeter, 400/pixelsPerMeter/2);
			wallB = world.CreateBody(wallBd); // Box2D handles the creation of a new b2Body for us.
			wallB.CreateFixture2(wall);
			// Right
			wallBd.position.Set((640 + 95) / pixelsPerMeter, 400 / pixelsPerMeter / 2);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			// Top
			wallBd.position.Set(640 / pixelsPerMeter / 2, -95 / pixelsPerMeter);
			wall.SetAsBox(680/pixelsPerMeter/2, 100/pixelsPerMeter);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			// Bottom
			wallBd.position.Set(640 / pixelsPerMeter / 2, (400 + 95) / pixelsPerMeter);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
 
		}
登入後複製

     在本教程的前面我们描述了创建一个对象的步骤。当时你可能感觉它有点混淆不清。但是在这里,你将看到它起到的作用,它是非常清晰的。

    第8-10行   我们声明了我们需要的变量。我们将要创建4座墙,因此我们每次会重用相同的变量。由于这些对象都是不动的,我们没必要为他们创建fixture来定义密度以及其他属性。Box2D创建的默认的fixture对于不懂的刚体来说已经非常完美了。

     我们只需要使用一个BodyDefinition,一个Shape,每次让Box2D创建刚体的时候改变他们的参数就行了。把这当作一个可以重用的有顺序的表单,box2D世界通过它创建实际的刚体。但是每个刚体创建后,已获得参数的刚体和表单间就没有联系了。因此,如果你改变了表单,并将它传递给了Box2D世界,你将获得一个新的顺序表单创建的新的刚体。事实上,你可能会经常提交相同的BodyDefinition,box2D会一遍又一遍的创建一个匹配你BodyDefinition的新的刚体。

     下面让我们来看看方块的创建。
     第13行 这里我们定义了新刚体的位置。它接收X,Y的坐标参数。但是为什么会复杂的除两次?因为box2D以米和千克测量它的世界,而我们的游戏用像素测量它的世界。

            理解Box2D中的单位

             Box2D是根据以米和千克为其计量单位来设计的。这非常的方便,因为物理科学也是以米和千克为计量单位的。这能让Box2D对真实世界的现象进行真实的模拟。很明显,我们不能在任何方向都让一米和一像素等价。因此我们需要降低其比例。你可以设定你的比例,让一米等于一像素,但是这会让Box2D的运行效率降低,因为在Box2D中,1米和两米间的差异很大,很明显,但是在1像素与2像素间的差异基本上不可见。

            你必须在用户可见的计量单位与Box2D的计量单位间找到一个平衡点。按照惯例,用Box2D的程序员将30个像素设置为1米,这样对Box2D的性能和精确度来说是一个折中的办法。因此,当你想放一个对象进入Box2D世界的时候,让你的具体的像素位置除以你的比例。下面是如何将坐标转换的公式:         

                    pixels / pixelsPerMeter = box2DMeters;

                    box2DMeters * pixelsPerMeter = pixels;

           请记住最后一点。Box2D刚体的注册点在其几何中心。因此,以他们的左上角为特殊点摆放物体,你会看到那些数字都除了2.比如:如果你想创建一个100像素的正方形Box2D刚体,并将其坐标设为(0,0),你只会在屏幕上看到这个正方形的一半。要想将100x100的方形放置在屏幕的左上方,你需要将其坐标设为(100/2,100/2).

     第14行 在这里我们调用了SetAsBox()函数。这是创建不需要旋转的盒子的快捷函数。如果要创建需要旋转的盒子,就使用SetAsOrientedBox().
     第15行 我们让世界以我们的bodyDefinition为规范创建一个刚体。所有对bodyDefinition的改变都会在我们调用world.CreateBody()的时候发生作用。新建的刚体在我们对其添加东西前只是一个放置几何形状的空容器。从这一刻开始,任何对
bodyDefinition的改变只会影响后续使用world.CreateBody()创建的刚体。
     第16行 最后,我们添加方形给我们的刚体。现在,空的刚体包含了一个长方形。

     接着我们对其它的墙重复这个过程。在这点上,Box2D世界做得很好。不需要其它额外的工作。Box2D通过其内部数据进行模拟,不需要任何舞台上的对象工作。如果你是一个不需要GUI的通过linux命令行进行编程的人,你可以到此结束了,去管理数据库或其它的内容。

     当然,你是一个flash程序员。这意味着不看到它的运行情况就无法进行编程。好了,让我们来添加视觉元素到舞台,看看我们的世界看起来像个什么吧!

        使用DebugDraw来呈现在Box2D世界发生了什么

     使用内置的debug draw 类是呈现我们创建的Box2D世界的最快的方法。这并不奇特,只是一些矢量线和填充块,但这对于只想看看游戏引擎的效果而不担心游戏美工的我们来说已经很完美了。如何在Box2D中使用你自己的图形和影片剪辑不在本教程的讲述范围内。

    下面是添加debug draw的代码:

private function makeDebugDraw():void
		{
			// set debug draw
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			addChild(debugSprite);
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.3);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			world.SetDebugDraw(debugDraw);
		}
登入後複製


      要想使用b2DebugDraw 类,我们需要:
      创建b2DebugDraw类得实例,
      赋一个空的影片剪辑给它来进行所有的绘画。
      让世界使用这个b2DebugDraw实例。

    第4行 创建b2DebugDraw 类得实例。
    第5-6行 创建一个影片剪辑并添加到舞台。
    第7-10行 为影片剪辑设一些属性以控制其显示。需要注意的是,SetDrawScale 需要匹配我们的pixelsPerMeter ,以至于我们通过debug draw画出的东西能得到我们预期的状况。
    第11行 SetFlags() 告诉debug draw 我们需要显示的数据。你想要显示出什么只取决于几何(形状)或关节(joints),或其他属性。这个函数值得一些高级项目的二次运用。
    第12行 最后,告诉世界用这个b2DebugDraw 实例来绘制。

    要想在舞台看到东西的最后步骤就是运行Box2D世界,并更新debugDraw。
    我们在update函数中做这些。 

 

private function update(e:Event = null):void
		{
			world.Step(timestep, iterations, iterations);
			world.ClearForces();
			// Render
			world.DrawDebugData();
		}
登入後複製


    这个简单的函数更新b2world,当他被调用后,每隔很短的一段时间进行一次模拟。然后调用calls world.ClearForces()。现在不用担心这行了。在2.1a版本中,它已经变得可有可无了。但是现在你不得不在再次调用Step()前调用ClearForces() 。最后我们用world.DrawDebugdata()将box2D绘制在屏幕上。
    注意update(e:event) 有一个可选的事件参数。这是因为update函数将成为你的主游戏循环。它将会通过一个Timer事件每隔30毫秒左右更新一次。

    现在开始去测试你的动画吧。你会看到四个长方形从你的舞台边缘探出。恭喜,到此你已经迈过了Box2D基础的较困难的一部分。然后准备一下,我们将要添加一些东西到Box2D世界:一些实际物理碰撞。

     对于最后一步,我不打算再像前面那样进行极尽详尽的讲解:我们将依次通过几个for循环来添加各种刚体。
     将会有3个主要类型:方形,圆形,多边形。
     我们的世界的边界永远不会移动。其实是他们不能移动。但是所有这些新的刚体都会受重力影响坠落,并在途中发生碰撞。产生这样的差异的关键代码行就是:
                bodyDef.type = b2Body.b2_dynamicBody;
      在Box2D 2.1a中,刚体拥有3种可选状态。
        Static(静态刚体):永远不移动。
        Dynamic(动态刚体):当收到力的作用时会发生移动,比洞碰撞,冲力,重力。
        Kinematic(运动刚体):和静态刚体相比,就是它可以移动.它也同样不会被环境力所影响。(译者注:按照固定路线运动的物体,比如说电梯,运动的滚梯,运行的火车等等.)
      如果你将一个刚体设为Dynamic,并将其唤醒,它将会移动,直到到达一个休眠点.

      下面是用于添加一系列刚体的函数:

private function makeABunchOfDynamicBodies():void
		{
			var i:int
			var body:b2Body;
			var fd:b2FixtureDef;
			//Add rectangles
			for (i = 0; i  0.66) {
					polyDef.SetAsArray([
						new b2Vec2((-10 -Math.random()*10) / pixelsPerMeter, ( 10 +Math.random()*10) / pixelsPerMeter),
						new b2Vec2(( -5 -Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter),
						new b2Vec2((  5 +Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter),
						new b2Vec2(( 10 +Math.random() * 10) / pixelsPerMeter, ( 10 +Math.random() * 10) / pixelsPerMeter)
						]);
				}
				else if (Math.random() > 0.5)
				{
					var array:Array = [];
					array[0] = new b2Vec2(0, (10 +Math.random()*10) / pixelsPerMeter);
					array[2] = new b2Vec2((-5 -Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter);
					array[3] = new b2Vec2(( 5 +Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter);
					array[1] = new b2Vec2((array[0].x + array[2].x), (array[0].y + array[2].y));
					array[1].Multiply(Math.random()/2+0.8);
					array[4] = new b2Vec2((array[3].x + array[0].x), (array[3].y + array[0].y));
					array[4].Multiply(Math.random() / 2 + 0.8);
					polyDef.SetAsArray(array);
				}
				else
				{
					polyDef.SetAsArray([
						new b2Vec2(0, (10 +Math.random()*10) / pixelsPerMeter),
						new b2Vec2((-5 -Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter),
						new b2Vec2(( 5 +Math.random() * 10) / pixelsPerMeter, ( -10 -Math.random() * 10) / pixelsPerMeter)
					]);
				}
				fd = new b2FixtureDef();
				fd.shape = polyDef;
				fd.density = 1.0;
				fd.friction = 0.3;
				fd.restitution = 0.1;
				bodyDefP.position.Set((Math.random() * 400 + 120) / pixelsPerMeter, (Math.random() * 150 + 50) / pixelsPerMeter);
				bodyDefP.angle = Math.random() * Math.PI;
				body = world.CreateBody(bodyDefP);
				body.CreateFixture(fd);
			}
		}
登入後複製


      接下来,我们在构造函数中添加一个此函数的调用并置于makeDebugDraw()函数调用之后:
        makeABunchOfDynamicBodies()
      最后,我们需要添加一个事件侦听器来调用update.眼下,我们只调用了一次update,之后我们创建我们所有的东西。所以,我们能看到新的世界的第一个实例。不过,这并不是动画。
      为了让创建的东西移动,我们需要反复的调用world.Step() 。
      添加下面这行代码:
       addEventListener(Event.ENTER_FRAME, update);

      现在发布你的影片,你回看到一大堆的图形降落并发生碰撞。
      这差不多就是我们整个教程中所得出的效果了。这里有一些进一步的操作:
      添加一个混合了static 和dynamic 状态的图形,产生更有趣的碰撞。

      Box2d 包里面有很多的不错的例子,这些例子告诉你怎样实现帅得冒泡的效果

      下面是整个教程最完整的代码(怎么用,你懂的!使用Box2D制作AS3游戏2.1a版本Hello World Box2D):

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	// Bring In Box2D
	import Box2D.Dynamics.*
	import Box2D.Collision.*
	import Box2D.Collision.Shapes.*
	import Box2D.Dynamics.Joints.*
	import Box2D.Dynamics.Contacts.*
	import Box2D.Common.Math.*
 
	/**
	 * ...
	 * @author Zach
	 */
	public class Main extends Sprite
	{
		private var world:b2World;
		private var timestep:Number;
		private var iterations:uint;
		private var pixelsPerMeter:Number = 30;
 
		public function Main():void
		{
 
			makeWorld();
			makeWalls();
			makeDebugDraw();
			makeABunchOfDynamicBodies()
 
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
 
		}
 
		private function makeWorld():void
		{
			// Define the gravity vector
			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
			// Allow bodies to sleep
			var doSleep:Boolean = true;
			// Construct a world object
			world = new b2World(gravity, doSleep);
			world.SetWarmStarting(true);
			timestep = 1.0 / 30.0;
			iterations = 10;
 
		}
 
		private function makeWalls():void
		{
			// Note: I am assuming a stage size of 640x400;
			// These placements will put a row of boxes around an area that size.
 
			// We reuse the shape and Body Definitions.
			// Box2D creates a different body each time we call world.CreateBody(wallBd);
			var wall:b2PolygonShape= new b2PolygonShape();
			var wallBd:b2BodyDef = new b2BodyDef();
			var wallB:b2Body;
 
			// Left
			wallBd.position.Set( -95 / pixelsPerMeter, 400 / pixelsPerMeter / 2);
			wall.SetAsBox(100/pixelsPerMeter, 400/pixelsPerMeter/2);
			wallB = world.CreateBody(wallBd); // Box2D handles the creation of a new b2Body for us.
			wallB.CreateFixture2(wall);
			// Right
			wallBd.position.Set((640 + 95) / pixelsPerMeter, 400 / pixelsPerMeter / 2);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			// Top
			wallBd.position.Set(640 / pixelsPerMeter / 2, -95 / pixelsPerMeter);
			wall.SetAsBox(680/pixelsPerMeter/2, 100/pixelsPerMeter);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
			// Bottom
			wallBd.position.Set(640 / pixelsPerMeter / 2, (400 + 95) / pixelsPerMeter);
			wallB = world.CreateBody(wallBd);
			wallB.CreateFixture2(wall);
 
		}
 
		private function makeDebugDraw():void
		{
			// set debug draw
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			addChild(debugSprite);
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.3);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			world.SetDebugDraw(debugDraw);
		}
 
		private function makeABunchOfDynamicBodies():void
		{
			var i:int
			var body:b2Body;
			var fd:b2FixtureDef;
			//Add rectangles
			for (i = 0; i  0.66) {
					polyDef.SetAsArray([
						new b2Vec2((-10 -Math.random()*10) / pixelsPerMeter, ( 10 +Math.random()*10) / pixelsPerMeter),
						new b2Vec2(( -5 -Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter),
						new b2Vec2((  5 +Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter),
						new b2Vec2(( 10 +Math.random() * 10) / pixelsPerMeter, ( 10 +Math.random() * 10) / pixelsPerMeter)
						]);
				}
				else if (Math.random() > 0.5)
				{
					var array:Array = [];
					array[0] = new b2Vec2(0, (10 +Math.random()*10) / pixelsPerMeter);
					array[2] = new b2Vec2((-5 -Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter);
					array[3] = new b2Vec2(( 5 +Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter);
					array[1] = new b2Vec2((array[0].x + array[2].x), (array[0].y + array[2].y));
					array[1].Multiply(Math.random()/2+0.8);
					array[4] = new b2Vec2((array[3].x + array[0].x), (array[3].y + array[0].y));
					array[4].Multiply(Math.random() / 2 + 0.8);
					polyDef.SetAsArray(array);
				}
				else
				{
					polyDef.SetAsArray([
						new b2Vec2(0, (10 +Math.random()*10) / pixelsPerMeter),
						new b2Vec2((-5 -Math.random()*10) / pixelsPerMeter, (-10 -Math.random()*10) / pixelsPerMeter),
						new b2Vec2(( 5 +Math.random() * 10) / pixelsPerMeter, ( -10 -Math.random() * 10) / pixelsPerMeter)
					]);
				}
				fd = new b2FixtureDef();
				fd.shape = polyDef;
				fd.density = 1.0;
				fd.friction = 0.3;
				fd.restitution = 0.1;
				bodyDefP.position.Set((Math.random() * 400 + 120) / pixelsPerMeter, (Math.random() * 150 + 50) / pixelsPerMeter);
				bodyDefP.angle = Math.random() * Math.PI;
				body = world.CreateBody(bodyDefP);
				body.CreateFixture(fd);
			}
		}
 
		private function init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			update();
			addEventListener(Event.ENTER_FRAME, update);
		}
 
		private function update(e:Event = null):void
		{
			world.Step(timestep, iterations, iterations);
			world.ClearForces();
			// Render
			world.DrawDebugData();
		}
 
	}
 
}
登入後複製



 


 

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1667
14
CakePHP 教程
1426
52
Laravel 教程
1328
25
PHP教程
1273
29
C# 教程
1255
24
Nvgpucomp64.dll導致Windows PC遊戲崩潰; Nvgpucomp64.dll導致Windows PC遊戲崩潰; Mar 26, 2024 am 08:20 AM

如果Nvgpucomp64.dll導致遊戲經常崩潰,這裡提供的解決方案可能會對您有所幫助。這種問題通常是由於過時或損壞的顯示卡驅動程式、遊戲檔案損壞等原因引起的。修復這些問題可以幫助您解決遊戲崩潰的困擾。 Nvgpucomp64.dll檔案與NVIDIA顯示卡關聯。當這個檔案崩潰時,你的遊戲也會崩潰。這通常發生在《LordsoftheFallen》、《LiesofP》、《RocketLeague》和《ApexLegends》等遊戲中。 Nvgpucomp64.dll使WindowsPC上的遊戲崩潰如果N

超級人類(superpeople)遊戲下載安裝方法介紹 超級人類(superpeople)遊戲下載安裝方法介紹 Mar 30, 2024 pm 04:01 PM

超級人類(superpeople)遊戲可以透過steam客戶端下載遊戲,這款遊戲的大小在28G左右,下載到安裝通常需要一個半小時​​,以下為大家帶來具體的下載安裝教學!新的申請全球封閉測試方法1)在Steam商店(steam客戶端下載)搜尋“SUPERPEOPLE”2)點擊“SUPERPEOPLE”商店頁面下方的“請求SUPERPEOPLE封閉測試訪問權限”3)點擊請求訪問權限按鈕後,將在Steam庫中可確認「SUPERPEOPLECBT」遊戲4)在「SUPERPEOPLECBT」中點選安裝按鈕並下

大模型一對一戰鬥75萬輪,GPT-4奪冠,Llama 3位列第五 大模型一對一戰鬥75萬輪,GPT-4奪冠,Llama 3位列第五 Apr 23, 2024 pm 03:28 PM

關於Llama3,又有測試結果新鮮出爐-大模型評測社群LMSYS發布了一份大模型排行榜單,Llama3位列第五,英文單項與GPT-4並列第一。圖片不同於其他Benchmark,這份榜單的依據是模型一對一battle,由全網測評者自行命題並評分。最終,Llama3取得了榜單中的第五名,排在前面的是GPT-4的三個不同版本,以及Claude3超大杯Opus。而在英文單項榜單中,Llama3反超了Claude,與GPT-4打成了平手。對於這一結果,Meta的首席科學家LeCun十分高興,轉發了推文並

華碩發表 BIOS 更新,提升英特爾第 13/14 代處理器遊戲穩定性 華碩發表 BIOS 更新,提升英特爾第 13/14 代處理器遊戲穩定性 Apr 20, 2024 pm 05:01 PM

本站4月20日消息,華碩公司近日發布了BIOS更新,改善了英特爾第13/14代處理器運行遊戲時崩潰等不穩定情況。本站先前報導,玩家回饋的問題包括運行萬代南夢宮格鬥遊戲《鐵拳8》PC演示版時,即便電腦擁有充足的記憶體和顯存,也會出現系統崩潰並提示記憶體不足的錯誤訊息。類似的崩潰問題也出現在《戰地風雲2042》、《遺跡2》、《要塞英雄》、《墮落之主》、《霍格華茲之遺》以及《TheFinals》等多款遊戲中。 RAD公司今年2月發布長文,解釋遊戲崩潰問題是BIOS設定、英特爾處理器的高時脈頻率和高功耗共同

BTCC教學:如何在BTCC交易所綁定使用MetaMask錢包? BTCC教學:如何在BTCC交易所綁定使用MetaMask錢包? Apr 26, 2024 am 09:40 AM

MetaMask(中文也叫小狐狸錢包)是一款免費的、廣受好評的加密錢包軟體。目前,BTCC已支援綁定MetaMask錢包,綁定後可使用MetaMask錢包進行快速登錄,儲值、買幣等,且首次綁定還可獲得20USDT體驗金。在BTCCMetaMask錢包教學中,我們將詳細介紹如何註冊和使用MetaMask,以及如何在BTCC綁定並使用小狐狸錢包。 MetaMask錢包是什麼? MetaMask小狐狸錢包擁有超過3,000萬用戶,是當今最受歡迎的加密貨幣錢包之一。它可免費使用,可作為擴充功能安裝在網絡

網易信箱大師怎麼用 網易信箱大師怎麼用 Mar 27, 2024 pm 05:32 PM

網易郵箱,作為中國網友廣泛使用的一種電子郵箱,一直以來以其穩定、高效的服務贏得了用戶的信賴。而網易信箱大師,則是專為手機使用者打造的信箱軟體,它大大簡化了郵件的收發流程,讓我們的郵件處理變得更加便利。那麼網易信箱大師該如何使用,具體又有哪些功能呢,下文中本站小編將為大家帶來詳細的內容介紹,希望能幫助到大家!首先,您可以在手機應用程式商店搜尋並下載網易信箱大師應用程式。在應用寶或百度手機助手中搜尋“網易郵箱大師”,然後按照提示進行安裝即可。下載安裝完成後,我們打開網易郵箱帳號並進行登錄,登入介面如下圖所示

百度網盤app怎麼用 百度網盤app怎麼用 Mar 27, 2024 pm 06:46 PM

在如今雲端儲存已成為我們日常生活和工作中不可或缺的一部分。百度網盤作為國內領先的雲端儲存服務之一,憑藉其強大的儲存功能、高效的傳輸速度以及便捷的操作體驗,贏得了廣大用戶的青睞。而且無論你是想要備份重要文件、分享資料,還是在線上觀看影片、聽取音樂,百度網盤都能滿足你的需求。但很多用戶可能對百度網盤app的具體使用方法還不了解,那麼這篇教學就將為大家詳細介紹百度網盤app如何使用,還有疑惑的用戶們就快來跟著本文詳細了解一下吧!百度雲網盤怎麼用:一、安裝首先,下載並安裝百度雲軟體時,請選擇自訂安裝選

為 PS5 Pro 鋪路,《無人深空》更新代碼「驚現」遊戲機開發代號「Trinity」及畫質設定檔 為 PS5 Pro 鋪路,《無人深空》更新代碼「驚現」遊戲機開發代號「Trinity」及畫質設定檔 Jul 22, 2024 pm 01:10 PM

本站7月22日消息,外媒twistedvoxel在《無人深空》最新的「世界第一部分」更新代碼中發現了傳聞中PS5的開發代號「Trinity」及相關畫質配置文件,佐證了索尼有望近期推出PS5Pro機種。雖然《無人深空》在近期的更新中已為遊戲加強了畫質表現,但仍有不少玩家認為這可能是HelloGames為新機型所提前鋪路,根據最新的圖形預設,在PS5Pro下這款遊戲的動態解析度縮放從0.6增加到0.8,這代表遊戲平均解析度更高,一些圖形細節從「High」級別升級到「Ultra」級別,不過由於每款遊戲

See all articles