custom textures and Shapes

    技术2025-09-22  81

     

    So in Part 3 of this series we will be moving awayfrom relying on the debug draw and SetAsBox function, and, instead wewill be creating custom shapes and textures by building a truck in ourBox2D world. This process is relatively simple but there are a fewcaveats.

    To save time I will be extending the MouseJoint class from Part 2to avoid recoding everything from scratch. Also, I am going to post thesource code upfront and then explain the process since we jump around abit making it difficult to post code snippets without adding confusion.

    package { import Box2D.Collision.Shapes.b2CircleShape; import Box2D.Dynamics.Joints.b2RevoluteJointDef; import Box2D.Dynamics.b2World; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2Body; import Box2D.Collision.Shapes.b2PolygonShape; import Box2D.Dynamics.b2FixtureDef; import flash.display.MovieClip; //import Box2D.Dynamics.b2DebugDraw; removed import flash.events.Event; import General.Input; public class CustomShapesTexturesTutorial extends MouseJointTutorial { protected var _truckBodySkin:MovieClip; protected var _boxSkin:MovieClip; protected var _truck:b2Body; protected var _box:b2Body; protected var _wheel1:b2Body; protected var _wheel2:b2Body; protected var _wheel3:b2Body; protected var _wheel1Skin:MovieClip; protected var _wheel2Skin:MovieClip; protected var _wheel3Skin:MovieClip; override protected function setup():void { _box = createBox(400, 30, 30, 30); createBoxSkin(); } override protected function init():void { _world = new b2World(new b2Vec2(0, 10), true); var groundBodyDef:b2BodyDef = new b2BodyDef(); groundBodyDef.position.Set(SWF_HALF_WIDTH / PIXELS_TO_METRE, SWF_HEIGHT / PIXELS_TO_METRE - 20 / PIXELS_TO_METRE); _groundBody = _world.CreateBody(groundBodyDef); var groundBox:b2PolygonShape = new b2PolygonShape(); groundBox.SetAsBox(SWF_HALF_WIDTH / PIXELS_TO_METRE, 20 / PIXELS_TO_METRE); var groundFixtureDef:b2FixtureDef = new b2FixtureDef(); groundFixtureDef.shape = groundBox; groundFixtureDef.density = 1; groundFixtureDef.friction = 1; _groundBody.CreateFixture(groundFixtureDef); createGroundSkin(); //removed all the debug stuff /*var debugSprite:Sprite = new Sprite(); addChild(debugSprite); var debugDraw:b2DebugDraw = new b2DebugDraw(); debugDraw.SetSprite(debugSprite); debugDraw.SetDrawScale(PIXELS_TO_METRE); debugDraw.SetLineThickness(1.0); debugDraw.SetAlpha(1); debugDraw.SetFillAlpha(0.4); debugDraw.SetFlags(b2DebugDraw.e_shapeBit); _world.SetDebugDraw(debugDraw);*/ _input = new Input(stage); createTruckBodySkin(); createTruckBody(); createTruckWheels(); createTruckWheelSkins(); addEventListener(Event.ENTER_FRAME, update); } private function createTruckWheelSkins():void { _wheel1Skin = new WheelSkin(); _wheel2Skin = new WheelSkin(); _wheel3Skin = new WheelSkin(); addChild(_wheel1Skin); addChild(_wheel2Skin); addChild(_wheel3Skin); } private function createTruckWheels():void { _wheel1 = createCircle(244, 350, 21); _wheel2 = createCircle(314, 350, 21); _wheel3 = createCircle(562, 350, 21); var firstWheelRevoluteJointDef:b2RevoluteJointDef = new b2RevoluteJointDef(); firstWheelRevoluteJointDef.Initialize(_wheel1, _truck, _wheel1.GetWorldCenter()); _world.CreateJoint(firstWheelRevoluteJointDef); var secondWheelRevoluteJointDef:b2RevoluteJointDef = new b2RevoluteJointDef(); secondWheelRevoluteJointDef.Initialize(_wheel2, _truck, _wheel2.GetWorldCenter()); _world.CreateJoint(secondWheelRevoluteJointDef); var thirdWheelRevoluteJointDef:b2RevoluteJointDef = new b2RevoluteJointDef(); thirdWheelRevoluteJointDef.Initialize(_wheel3, _truck, _wheel3.GetWorldCenter()); _world.CreateJoint(thirdWheelRevoluteJointDef); } private function createCircle(x:int,y:int,radius:int):b2Body { var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.type = b2Body.b2_dynamicBody; bodyDef.position.Set(x / PIXELS_TO_METRE, y / PIXELS_TO_METRE); var body:b2Body = _world.CreateBody(bodyDef); var dynamicCircle:b2CircleShape = new b2CircleShape(radius / PIXELS_TO_METRE); var fixtureDef:b2FixtureDef = new b2FixtureDef(); fixtureDef.shape = dynamicCircle; fixtureDef.density = 1; fixtureDef.friction = 0.4;//decent friction in tires, but not so much that the wheels can't spin out body.CreateFixture(fixtureDef); return body; } private function createTruckBodySkin():void { _truckBodySkin = new TruckBody(); addChild(_truckBodySkin); } private function createGroundSkin():void { var groundSkin:MovieClip = new GroundSkin(); addChild(groundSkin); groundSkin.x = _groundBody.GetPosition().x * PIXELS_TO_METRE; groundSkin.y = _groundBody.GetPosition().y * PIXELS_TO_METRE; } private function createBoxSkin():void { _boxSkin = new BoxSkin(); addChild(_boxSkin); _boxSkin.x = _box.GetPosition().x * PIXELS_TO_METRE; _boxSkin.y = _box.GetPosition().y * PIXELS_TO_METRE; } private function createTruckBody():void { var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.type = b2Body.b2_dynamicBody; bodyDef.position.Set(400 / PIXELS_TO_METRE, 300 / PIXELS_TO_METRE); _truck = _world.CreateBody(bodyDef); /* * p5-----------------------------p6 * | | * /-p2 | | * p1/ | | | * | | | | * p4----p3 p8-----------------------------p7 */ //Truck cab //--------------------------- var truckCabShape:b2PolygonShape = new b2PolygonShape(); //clockwise var p1:b2Vec2 = new b2Vec2(-193.8 / PIXELS_TO_METRE, 5 / PIXELS_TO_METRE); var p2:b2Vec2 = new b2Vec2(-123 / PIXELS_TO_METRE, -17.3 / PIXELS_TO_METRE); var p3:b2Vec2 = new b2Vec2(-123 / PIXELS_TO_METRE, 54.5 / PIXELS_TO_METRE); var p4:b2Vec2 = new b2Vec2(-193.8 / PIXELS_TO_METRE, 54.5 / PIXELS_TO_METRE); var cabVertices:Array = [p1,p2,p3,p4]; truckCabShape.SetAsArray(cabVertices); var truckCabFixtureDef:b2FixtureDef = new b2FixtureDef(); truckCabFixtureDef.shape = truckCabShape; truckCabFixtureDef.density = 1; truckCabFixtureDef.friction = 0.3; _truck.CreateFixture(truckCabFixtureDef); //Truck cargo //--------------------------- var truckCargoShape:b2PolygonShape = new b2PolygonShape(); //clockwise var p5:b2Vec2 = new b2Vec2(-123 / PIXELS_TO_METRE, -54.6 / PIXELS_TO_METRE); var p6:b2Vec2 = new b2Vec2(194 / PIXELS_TO_METRE, -54.6 / PIXELS_TO_METRE); var p7:b2Vec2 = new b2Vec2(194 / PIXELS_TO_METRE, 54.5 / PIXELS_TO_METRE); var p8:b2Vec2 = new b2Vec2(-123 / PIXELS_TO_METRE, 54.5 / PIXELS_TO_METRE); var bodyVertices:Array = [p5,p6,p7,p8]; truckCargoShape.SetAsArray(bodyVertices); var truckCargoFixtureDef:b2FixtureDef = new b2FixtureDef(); truckCargoFixtureDef.shape = truckCargoShape; truckCargoFixtureDef.density = 1; truckCargoFixtureDef.friction = 0.3; _truck.CreateFixture(truckCargoFixtureDef); } protected function drawTruckBody():void { _truckBodySkin.x = _truck.GetPosition().x * PIXELS_TO_METRE; _truckBodySkin.y = _truck.GetPosition().y * PIXELS_TO_METRE; _truckBodySkin.rotation = _truck.GetAngle() * (180 / Math.PI); } protected function drawBox():void { _boxSkin.x = _box.GetPosition().x * PIXELS_TO_METRE; _boxSkin.y = _box.GetPosition().y * PIXELS_TO_METRE; _boxSkin.rotation = _box.GetAngle() * (180 / Math.PI); } protected function drawWheels():void { _wheel1Skin.x = _wheel1.GetPosition().x * PIXELS_TO_METRE; _wheel1Skin.y = _wheel1.GetPosition().y * PIXELS_TO_METRE; _wheel1Skin.rotation = _wheel1.GetAngle() * (180 / Math.PI); _wheel2Skin.x = _wheel2.GetPosition().x * PIXELS_TO_METRE; _wheel2Skin.y = _wheel2.GetPosition().y * PIXELS_TO_METRE; _wheel2Skin.rotation = _wheel2.GetAngle() * (180 / Math.PI); _wheel3Skin.x = _wheel3.GetPosition().x * PIXELS_TO_METRE; _wheel3Skin.y = _wheel3.GetPosition().y * PIXELS_TO_METRE; _wheel3Skin.rotation = _wheel3.GetAngle() * (180 / Math.PI); } override protected function update(e:Event):void { var timeStep:Number = 1 / 60; var velocityIterations:int = 6; var positionIterations:int = 2; UpdateMouseWorld(); MouseDestroy(); MouseDrag(); drawTruckBody(); drawBox(); drawWheels(); KeyboardUpdate(); _world.Step(timeStep, velocityIterations, positionIterations); _world.ClearForces(); //_world.DrawDebugData(); removed General.Input.update(); } private function KeyboardUpdate():void { if(General.Input.isKeyDown(37)) { _wheel1.ApplyTorque(-40); _wheel2.ApplyTorque(-40); _wheel3.ApplyTorque(-40); } if(General.Input.isKeyDown(39)) { _wheel1.ApplyTorque(40); _wheel2.ApplyTorque(40); _wheel3.ApplyTorque(40); } } } }

     

    Displaying textures

    So in the previous tutorials we have been relying on the debug rendering to display our world. As useful as it is, it would be nice to apply some textures so lets fire up the Flash IDE and create the textures.

    For this truck, will need to draw the truck body, a wheel and the ground. It is important that each of these MovieClip’s has the registration point in the middle. When you have finished creating the images set the linkage on them so we can create the MovieClips via code.

    Lets make the bodies. It is the same process from the previous tutorials.  We will need to create the truck body, the three wheel bodies with revolute joints, and the ground body. Make sure all the debug drawing code is removed. Now we will create instances of the MovieClips that we created in the Flash IDE as set them as class member variables.  Time to draw. Create a draw function (or multiple draw functions for each body if you like) and call it from your update function. In this draw function we will get the x and y position of a body and set the relevant texture MoveClip to this position. We will also set the rotation as well – just don’t forget to convert to degrees from radians.

    Custom shapes:

    Now that we have our drawing code in place, we need to create the shapes that the Box2D engine uses for its calculations.

    Previously we had been calling a helper function to create a box for us. So this time, we will create a b2PolygonShape, but instead of calling SetAsBox we will pass in a array of b2Vec2 vertices that outline the truck.

    Note, there are two main restrictions. The first is that we pass in the vertices in a clock wise direction. The second is that Box2D does not allow concave shapes. We can see that where the cab joins the cargo that it is a concave shape. The solution is that we will need to break the truck up into two convex shapes – the cab and the cargo.

    I have updated the class diagram that I used in Part 1 to break down how the truck is being made.

    So create a b2PolygonShape for the truck’s cab and cargo. Create the vertices, place them in an array and pass this as a parameter in SetAsArray function on each of the b2PolygonShape. As of Box2D 2.1a we no longer are restricted to just 8 vertex points per shape. Create a b2FixtureDef  for each b2PolygonShape. Set the shape property on the b2FixtureDef  to the corresponding b2PolygonShape. Call the CreateFixture function on the truck body twice, once for the cab by passing in the cab’s b2FixtureDef and then the cargo b2FixtureDef.

    That’s it. We are done,  run your code and you should now see our truck in the world!

     

    原文地址:http://blog.allanbishop.com/box2d-2-1a-tutorial-%E2%80%93-part-3-custom-textures-and-shapes/

     

    最新回复(0)