其他分享
首页 > 其他分享> > TopDown Car demo

TopDown Car demo

作者:互联网

  1 //这个是老外教程附带的文件,直接复制下来放到Testbed例子的目录。你懂得 
  2 /* * Author: Chris Campbell - www.iforce2d.net * * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org *
  3    * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software.
  4    * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions:
  5    * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required.
  6    * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software.
  7    * 3. This notice may not be removed or altered from any source distribution. */
  8 #ifndef IFORCE2D_TOPDOWN_CAR_H
  9 #define IFORCE2D_TOPDOWN_CAR_H
 10 #include #include 
 11 #ifndef DEGTORAD 
 12 #define DEGTORAD 0.0174532925199432957f
 13 #define RADTODEG 57.295779513082320876f
 14 #endif
 15 enum {
 16     TDC_LEFT = 0x1,
 17     TDC_RIGHT = 0x2,
 18     TDC_UP = 0x4,
 19     TDC_DOWN = 0x8
 20 }; //types of fixture user data
 21 enum fixtureUserDataType
 22 {
 23     FUD_CAR_TIRE,
 24     FUD_GROUND_AREA
 25 }; //a class to allow subclassing of different fixture user data
 26 class FixtureUserData {
 27     fixtureUserDataType m_type;
 28 protected:
 29     FixtureUserData(fixtureUserDataType type) : m_type(type) {}
 30 public:
 31     virtual fixtureUserDataType getType() {
 32         return m_type;
 33     }
 34     virtual ~FixtureUserData()
 35     {
 36     }
 37 }; //class to allow marking a fixture as a car tire 
 38 class CarTireFUD : public FixtureUserData
 39 {
 40 public:
 41     CarTireFUD() : FixtureUserData(FUD_CAR_TIRE) {}
 42 };
 43 //class to allow marking a fixture as a ground area 
 44 class GroundAreaFUD : public FixtureUserData {
 45 public:
 46     float frictionModifier;
 47     bool outOfCourse;
 48     GroundAreaFUD(float fm, bool ooc) : FixtureUserData(FUD_GROUND_AREA)
 49     {
 50         frictionModifier = fm; outOfCourse = ooc;
 51     }
 52 };
 53 class TDTire
 54 {
 55 public:
 56     b2Body* m_body;
 57     float m_maxForwardSpeed;
 58     float m_maxBackwardSpeed;
 59     float m_maxDriveForce;
 60     float m_maxLateralImpulse;
 61     std::set m_groundAreas;
 62     float m_currentTraction;
 63     TDTire(b2World* world) {
 64         b2BodyDef bodyDef;
 65         bodyDef.type = b2_dynamicBody;
 66         m_body = world->CreateBody(&bodyDef);
 67         b2PolygonShape polygonShape;
 68         polygonShape.SetAsBox(0.5f, 1.25f);
 69         b2Fixture* fixture = m_body->CreateFixture(&polygonShape, 1);//shape, density 
 70         fixture->SetUserData(new CarTireFUD());
 71         m_body->SetUserData(this);
 72         m_currentTraction = 1;
 73     }
 74     ~TDTire() { m_body->GetWorld()->DestroyBody(m_body); }
 75     void setCharacteristics(float maxForwardSpeed, float maxBackwardSpeed, float maxDriveForce, float maxLateralImpulse)
 76     {
 77         m_maxForwardSpeed = maxForwardSpeed; m_maxBackwardSpeed = maxBackwardSpeed; m_maxDriveForce = maxDriveForce;
 78         m_maxLateralImpulse = maxLateralImpulse;
 79     }
 80     void addGroundArea(GroundAreaFUD* ga) {
 81         m_groundAreas.insert(ga);
 82         updateTraction();
 83     } void removeGroundArea(GroundAreaFUD* ga) { m_groundAreas.erase(ga); updateTraction(); }
 84     void updateTraction() {
 85         if (m_groundAreas.empty()) m_currentTraction = 1; else { //find area with highest traction
 86             m_currentTraction = 0; std::set::iterator it = m_groundAreas.begin();
 87             while (it != m_groundAreas.end()) { GroundAreaFUD* ga = *it; if (ga->frictionModifier > m_currentTraction) m_currentTraction = ga->frictionModifier; ++it; }
 88         }
 89     }
 90     b2Vec2 getLateralVelocity() {
 91         b2Vec2 currentRightNormal = m_body->GetWorldVector(b2Vec2(1, 0));
 92         return b2Dot(currentRightNormal, m_body->GetLinearVelocity()) * currentRightNormal;
 93     }
 94     b2Vec2 getForwardVelocity() {
 95         b2Vec2 currentForwardNormal = m_body->GetWorldVector(b2Vec2(0, 1));
 96         return b2Dot(currentForwardNormal, m_body->GetLinearVelocity()) * currentForwardNormal;
 97     }
 98     void updateFriction() { //lateral linear velocity 
 99         b2Vec2 impulse = m_body->GetMass() * -getLateralVelocity();
100         if (impulse.Length() > m_maxLateralImpulse)
101             impulse *= m_maxLateralImpulse / impulse.Length();
102         m_body->ApplyLinearImpulse(m_currentTraction * impulse, m_body->GetWorldCenter()); //angular velocity
103         m_body->ApplyAngularImpulse(m_currentTraction * 0.1f * m_body->GetInertia() * -m_body->GetAngularVelocity()); //forward linear velocity 
104         b2Vec2 currentForwardNormal = getForwardVelocity();
105         float currentForwardSpeed = currentForwardNormal.Normalize();
106         float dragForceMagnitude = -2 * currentForwardSpeed;
107         m_body->ApplyForce(m_currentTraction * dragForceMagnitude * currentForwardNormal, m_body->GetWorldCenter());
108     }
109     void updateDrive(int controlState) { //find desired speed 
110         float desiredSpeed = 0;
111         switch (controlState & (TDC_UP | TDC_DOWN))
112         {
113         case TDC_UP: desiredSpeed = m_maxForwardSpeed; break;
114         case TDC_DOWN: desiredSpeed = m_maxBackwardSpeed; break;
115         default: return;//do nothing } //find current speed in forward direction 
116             b2Vec2 currentForwardNormal = m_body->GetWorldVector(b2Vec2(0, 1));
117             float currentSpeed = b2Dot(getForwardVelocity(), currentForwardNormal); //apply necessary force 
118             float force = 0;
119             if (desiredSpeed > currentSpeed)
120                 force = m_maxDriveForce;
121             else if (desiredSpeed < currentSpeed)
122                 force = -m_maxDriveForce; else return;
123             m_body->ApplyForce(m_currentTraction * force * currentForwardNormal, m_body->GetWorldCenter());
124         }
125         void updateTurn(int controlState) {
126             float desiredTorque = 0;
127             switch (controlState & (TDC_LEFT | TDC_RIGHT))
128             {
129             case TDC_LEFT:
130                 desiredTorque = 15;
131                 break;
132             case TDC_RIGHT:
133                 desiredTorque = -15;
134                 break;
135             default:;//nothing 
136             }
137             m_body->ApplyTorque(desiredTorque);
138         }
139     };
140 }
141 class TDCar {
142     b2Body* m_body;
143     std::vector m_tires;
144     b2RevoluteJoint* flJoint, * frJoint;
145 public:
146     TDCar(b2World* world)
147     {
148         //create car body
149         b2BodyDef bodyDef;
150         bodyDef.type = b2_dynamicBody; m_body = world->CreateBody(&bodyDef);
151         m_body->SetAngularDamping(3); b2Vec2 vertices[8]; vertices[0].Set(1.5, 0);
152         vertices[1].Set(3, 2.5); vertices[2].Set(2.8, 5.5); vertices[3].Set(1, 10);
153         vertices[4].Set(-1, 10); vertices[5].Set(-2.8, 5.5); vertices[6].Set(-3, 2.5);
154         vertices[7].Set(-1.5, 0); b2PolygonShape polygonShape; polygonShape.Set(vertices, 8);
155         b2Fixture* fixture = m_body->CreateFixture(&polygonShape, 0.1f);//shape, density //prepare common joint parameters 
156         b2RevoluteJointDef jointDef;
157         jointDef.bodyA = m_body;
158         jointDef.enableLimit = true;
159         jointDef.lowerAngle = 0;
160         jointDef.upperAngle = 0;
161         jointDef.localAnchorB.SetZero();//center of tire float maxForwardSpeed = 250; float maxBackwardSpeed = -40; float backTireMaxDriveForce = 300; float frontTireMaxDriveForce = 500; float backTireMaxLateralImpulse = 8.5; float frontTireMaxLateralImpulse = 7.5; //back left tire TDTire* tire = new TDTire(world); tire->setCharacteristics(maxForwardSpeed, maxBackwardSpeed, backTireMaxDriveForce, backTireMaxLateralImpulse); jointDef.bodyB = tire->m_body; jointDef.localAnchorA.Set( -3, 0.75f ); world->CreateJoint( &jointDef ); m_tires.push_back(tire); //back right tire tire = new TDTire(world); tire->setCharacteristics(maxForwardSpeed, maxBackwardSpeed, backTireMaxDriveForce, backTireMaxLateralImpulse); jointDef.bodyB = tire->m_body; jointDef.localAnchorA.Set( 3, 0.75f ); world->CreateJoint( &jointDef ); m_tires.push_back(tire); //front left tire tire = new TDTire(world); tire->setCharacteristics(maxForwardSpeed, maxBackwardSpeed, frontTireMaxDriveForce, frontTireMaxLateralImpulse); jointDef.bodyB = tire->m_body; jointDef.localAnchorA.Set( -3, 8.5f ); flJoint = (b2RevoluteJoint*)world->CreateJoint( &jointDef ); m_tires.push_back(tire); //front right tire tire = new TDTire(world); tire->setCharacteristics(maxForwardSpeed, maxBackwardSpeed, frontTireMaxDriveForce, frontTireMaxLateralImpulse); jointDef.bodyB = tire->m_body; jointDef.localAnchorA.Set( 3, 8.5f ); frJoint = (b2RevoluteJoint*)world->CreateJoint( &jointDef ); m_tires.push_back(tire); } ~TDCar() { for (int i = 0; i < m_tires.size(); i++) delete m_tires[i]; } void update(int controlState) { for (int i = 0; i < m_tires.size(); i++) m_tires[i]->updateFriction();
162         for (int i = 0; i < m_tires.size(); i++)
163             m_tires[i]->updateDrive(controlState); //control steering 
164         float lockAngle = 35 * DEGTORAD;
165         float turnSpeedPerSec = 160 * DEGTORAD;//from lock to lock in 0.5 sec
166         float turnPerTimeStep = turnSpeedPerSec / 60.0f;
167         float desiredAngle = 0;
168         switch (controlState & (TDC_LEFT | TDC_RIGHT))
169         {
170         case TDC_LEFT:
171             desiredAngle = lockAngle;
172             break;
173         case TDC_RIGHT:
174             desiredAngle = -lockAngle;
175             break;
176         default:;//nothing 
177         }
178         float angleNow = flJoint->GetJointAngle();
179         float angleToTurn = desiredAngle - angleNow;
180         angleToTurn = b2Clamp(angleToTurn, -turnPerTimeStep, turnPerTimeStep);
181         float newAngle = angleNow + angleToTurn;
182         flJoint->SetLimits(newAngle, newAngle);
183         frJoint->SetLimits(newAngle, newAngle);
184     }
185 };
186 class MyDestructionListener : public b2DestructionListener {
187     void SayGoodbye(b2Fixture* fixture) {
188         if (FixtureUserData* fud = (FixtureUserData*)fixture->GetUserData())
189             delete fud;
190     } //(unused but must implement all pure virtual functions)
191     void SayGoodbye(b2Joint* joint) {}
192 };
193 class iforce2d_TopdownCar : public Test {
194 public:
195     iforce2d_TopdownCar()
196     {
197         m_world->SetGravity(b2Vec2(0, 0));
198         m_world->SetDestructionListener(&m_destructionListener); //set up ground areas 
199         {
200             b2BodyDef bodyDef; m_groundBody = m_world->CreateBody(&bodyDef);
201             b2PolygonShape polygonShape; b2FixtureDef fixtureDef;
202             fixtureDef.shape = &polygonShape; fixtureDef.isSensor = true;
203             polygonShape.SetAsBox(9, 7, b2Vec2(-10, 15), 20 * DEGTORAD);
204             b2Fixture* groundAreaFixture = m_groundBody->CreateFixture(&fixtureDef);
205             groundAreaFixture->SetUserData(new GroundAreaFUD(0.5f, false));
206             polygonShape.SetAsBox(9, 5, b2Vec2(5, 20), -40 * DEGTORAD);
207             groundAreaFixture = m_groundBody->CreateFixture(&fixtureDef);
208             groundAreaFixture->SetUserData(new GroundAreaFUD(0.2f, false));
209         } //
210         m_tire = new TDTire(m_world); //
211         m_tire->setCharacteristics(100, -20, 150);
212         m_car = new TDCar(m_world);
213         m_controlState = 0;
214     }
215 
216     ~iforce2d_TopdownCar() { //
217         delete m_tire; delete m_car; m_world->DestroyBody(m_groundBody);
218     }
219     void Keyboard(unsigned char key) {
220         switch (key) {
221         case 'a': m_controlState |= TDC_LEFT; break;
222         case 'd': m_controlState |= TDC_RIGHT; break;
223         case 'w': m_controlState |= TDC_UP; break;
224         case 's': m_controlState |= TDC_DOWN; break;
225         default: Test::Keyboard(key);
226         }
227     }
228     void KeyboardUp(unsigned char key)
229     {
230         switch (key) {
231         case 'a':
232             m_controlState &= ~TDC_LEFT; break;
233         case 'd':
234             m_controlState &= ~TDC_RIGHT;
235             break;
236         case 'w':
237             m_controlState &= ~TDC_UP;
238             break;
239         case 's':
240             m_controlState &= ~TDC_DOWN;
241             break;
242         default:
243             Test::Keyboard(key);
244         }
245     }
246     void handleContact(b2Contact* contact, bool began)
247     {
248         b2Fixture* a = contact->GetFixtureA();
249         b2Fixture* b = contact->GetFixtureB();
250         FixtureUserData* fudA = (FixtureUserData*)a->GetUserData();
251         FixtureUserData* fudB = (FixtureUserData*)b->GetUserData();
252         if (!fudA || !fudB)
253             return;
254         if (fudA->getType() == FUD_CAR_TIRE || fudB->getType() == FUD_GROUND_AREA)
255             tire_vs_groundArea(a, b, began);
256         else if (fudA->getType() == FUD_GROUND_AREA || fudB->getType() == FUD_CAR_TIRE)
257             tire_vs_groundArea(b, a, began);
258     }
259     void BeginContact(b2Contact* contact)
260     {
261         handleContact(contact, true);
262     }
263     void EndContact(b2Contact* contact)
264     {
265         handleContact(contact, false);
266     }
267     void tire_vs_groundArea(b2Fixture* tireFixture, b2Fixture* groundAreaFixture, bool began)
268     {
269         TDTire* tire = (TDTire*)tireFixture->GetBody()->GetUserData();
270         GroundAreaFUD* gaFud = (GroundAreaFUD*)groundAreaFixture->GetUserData();
271         if (began) tire->addGroundArea(gaFud); else tire->removeGroundArea(gaFud);
272     }
273     void Step(Settings* settings) {
274         /*m_tire->updateFriction();
275         m_tire->updateDrive(m_controlState);
276         m_tire->updateTurn(m_controlState);*/
277         m_car->update(m_controlState); Test::Step(settings); //show some useful info 
278         m_debugDraw.DrawString(5, m_textLine, "Press w/a/s/d to control the car");
279         m_textLine += 15; //
280         m_debugDraw.DrawString(5, m_textLine, "Tire traction: %.2f", m_tire->m_currentTraction); //
281         m_textLine += 15;
282     }
283     static Test* Create()
284     {
285         return new iforce2d_TopdownCar;
286     }
287     int m_controlState;
288     MyDestructionListener m_destructionListener;
289     b2Body* m_groundBody; //
290     TDTire* m_tire;
291     TDCar* m_car;
292 };
293 #endif
View Code

 

标签:body,tire,TDC,Car,TopDown,float,controlState,demo,world
来源: https://www.cnblogs.com/yang131/p/14372236.html