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 #endifView Code
标签:body,tire,TDC,Car,TopDown,float,controlState,demo,world 来源: https://www.cnblogs.com/yang131/p/14372236.html