Flatland

Documentation

SourceForge.net Logo

complex.cpp

Go to the documentation of this file.
00001 // Summary: More complex demo program for flatland.
00002 // Copyright: 2007  Philip Rideout.  All rights reserved.
00003 // License: see bsd-license.txt
00004 
00005 #include <ode/ode.h>
00006 #include "demo.hpp"
00007 #include "os.h"
00008 
00009 using namespace Demo;
00010 using Flatland::pi;
00011 using Flatland::aabb;
00012 using Flatland::ContactList;
00013 
00014 class ComplexApp : public App
00015 {
00016   public:
00017     ComplexApp(bool fullscreen);
00018     void InitWin();
00019     void InitGl();
00020     void Draw() const;
00021     void HandleEvents();
00022     void ProcessKeyState();
00023     void ToggleFullscreen();
00024     bool MouseMoved() const { return motion; }
00025     bool IsFullscreen() const { return fullscreen; }
00026     static int GetWidth(bool screen) { return screen ? osGetScreenWidth() : InitialWidth; }
00027     static int GetHeight(bool screen) { return screen ? osGetScreenHeight() : InitialHeight; }
00028     static const int InitialWidth = 1000;
00029     static const int InitialHeight = 600;
00030   private:
00031     void handle(const OS_Event &event);
00032     Texture helpTexture;
00033     Texture downTexture;
00034     Texture upTexture;
00035     Texture boostTexture;
00036     Texture wheelTexture;
00037     bool freeze;
00038     bool hover;
00039     bool pressed;
00040     bool fullscreen;
00041     bool motion;
00042     aabb scrollbox;
00043     vec2 scrolloffset;
00044     Wheel *wheel;
00045     Wheel *wheel2;
00046     dJointID motor;
00047     dJointID pendulumAnchor;
00048     dJointID bubbleAnchor;
00049     dJointID blockFeeder;
00050     dJointID squareWheelMotor;
00051     static void boostCallback(ContactList &contacts);
00052     static void pendulumCallback(ContactList &contacts);
00053     static void bubbleCallback(ContactList &contacts);
00054     static void feederCallback(ContactList &contacts);
00055 };
00056 
00057 /// Entry point.
00058 int main(int argc, char** argv)
00059 {
00060     // Instantiate the app object.
00061     const bool fullscreen = false;
00062     ComplexApp app(fullscreen);
00063 
00064     // Upper limit on draws per second.
00065     const float fps = 60;
00066     const unsigned int fDelay = (unsigned int) (1000.0f / fps);
00067 
00068     // Upper limit on simulation steps per second.
00069     const float sps = 1000;
00070     const unsigned int sDelay = (unsigned int) (1000.0f / sps);
00071 
00072     // Flags for upper limit on frames per second and steps per second.
00073     const bool capFps = true;
00074     const bool capSps = true;
00075     osWaitVsync(1);
00076 
00077     /// \note
00078     /// To capture movies with Fraps, set fps to 30 and comment out vsync.
00079     /// Don't forget to compress the movie with VirtualDub.
00080 
00081     // Simulation step size.
00082     const float delta = 0.25;
00083 
00084     // Delay before mouse cursor disappears when in fullscreen mode.
00085     const unsigned int mDelay = 2000;
00086 
00087     // Start the simulation loop. 
00088     unsigned int fTime, sTime, mTime;
00089     for (fTime = sTime = mTime = osGetMilliseconds();;)
00090     {
00091         // process all events
00092         app.HandleEvents();
00093 
00094         // obtain the current time
00095         unsigned int time = osGetMilliseconds();
00096 
00097         // draw the scene and do a page flip
00098         if (!capFps || time - fTime > fDelay)
00099         {
00100             app.Draw();
00101             osSwapBuffers();
00102             fTime = time;
00103         }
00104 
00105         // prevent the simulation from running too fast
00106         if (capSps && time - sTime < sDelay)
00107             continue;
00108         sTime = time;
00109 
00110         // update the simulation
00111         app.ProcessKeyState();
00112         app.Step(delta);
00113         app.UpdateCenter();
00114 
00115         // hide or show the mouse cursor if needed
00116         if (app.IsFullscreen())
00117         {
00118             if (app.MouseMoved())
00119             {
00120                 mTime = time;
00121                 if (!osShowCursor(OS_QUERY))
00122                     osShowCursor(OS_ENABLE);
00123             }
00124             else if (osShowCursor(OS_QUERY) && time - mTime > mDelay)
00125             {
00126                 osShowCursor(OS_DISABLE);
00127             }
00128         }
00129     }
00130 
00131     return 0;
00132 }
00133 
00134 #define app (static_cast<ComplexApp&>(App::GetSingleton()))
00135 
00136 /// Toggle fullscreen mode.  Stop and restart the graphics subsystems.
00137 void ComplexApp::ToggleFullscreen()
00138 {
00139     osQuit();
00140     fullscreen = !fullscreen;
00141     width = GetWidth(fullscreen);
00142     height = GetHeight(fullscreen);
00143     hover = false;
00144     InitWin();
00145     InitGl();
00146 }
00147 
00148 /// Handle all SDL events in the event queue.
00149 void ComplexApp::HandleEvents()
00150 {
00151     motion = false;
00152     OS_Event event;
00153     while (osPollEvent(&event))
00154         handle(event);
00155 }
00156 
00157 /// Handle a particular SDL event.
00158 void ComplexApp::handle(const OS_Event &event)
00159 {
00160     switch(event.type)
00161     {
00162         case OS_RESIZE:
00163             Resize(event.resize.width, event.resize.height);
00164             return;
00165 
00166         case OS_QUIT: exit(0);
00167 
00168         case OS_MOUSEBUTTONDOWN:
00169             pressed = hover && event.mouse.button == OS_BUTTON_LEFT;
00170             break;
00171 
00172         case OS_MOUSEBUTTONUP:
00173             if (event.mouse.button == OS_BUTTON_LEFT)
00174             {
00175                 pressed = false;
00176                 if (hover)
00177                     ToggleFullscreen();
00178             }
00179             break;
00180 
00181         case OS_MOUSEMOTION:
00182             if (osShowCursor(OS_QUERY))
00183             {
00184                 hover = event.mouse.x < TextureWidth(upTexture) + 2;
00185                 hover = hover && event.mouse.y < TextureHeight(upTexture);
00186             }
00187             pressed = hover && (event.mouse.button & OS_BUTTON_LEFT);
00188             motion = true;
00189             break;
00190 
00191         case OS_KEYDOWN:
00192             if (wheel && motor)
00193             {
00194                 float speed = world.GetMotorVelocity(motor);
00195                 if (speed > 0 && event.key.key == OSK_LEFT)
00196                 {
00197                     world.SetMotorVelocity(motor, 0);
00198                     freeze = true;
00199                 }
00200                 else if (speed < 0 && event.key.key == OSK_RIGHT)
00201                 {
00202                     world.SetMotorVelocity(motor, 0);
00203                     freeze = true;
00204                 }
00205             }
00206             break;
00207 
00208         case OS_KEYUP:
00209             switch (event.key.key)
00210             {
00211                 case 'x': case 'X': case 'q': case 'Q':
00212                 case OSK_ESCAPE: exit(0); break;
00213                 case OSK_LEFT: case OSK_RIGHT: freeze = false; break;
00214             }
00215             break;
00216     }
00217 }
00218 
00219 /// Handler for the keyboard state.
00220 void ComplexApp::ProcessKeyState()
00221 {
00222     if (osIsKeyDown(OSK_SHIFT))
00223     {
00224         const float d = 1;
00225         if (osIsKeyDown(OSK_LEFT)) scrolloffset.x -= d;
00226         else if (osIsKeyDown(OSK_RIGHT)) scrolloffset.x += d;
00227         else if (osIsKeyDown(OSK_UP)) scrolloffset.y -= d;
00228         else if (osIsKeyDown(OSK_DOWN)) scrolloffset.y += d;
00229     }
00230     else
00231     {
00232         scrolloffset = vec2(0, 0);
00233     }
00234 
00235     if (wheel && motor && !freeze && scrolloffset.x == 0 && scrolloffset.y == 0)
00236     {
00237         const float speed = world.GetMotorVelocity(motor);
00238         const float delta = 0.001f;
00239         const float max = 0.1f;
00240 
00241         if (osIsKeyDown(OSK_LEFT) && speed > -max)
00242             world.SetMotorVelocity(motor, speed - delta);
00243         else if (osIsKeyDown(OSK_RIGHT) && speed < max)
00244             world.SetMotorVelocity(motor, speed + delta);
00245     }
00246 
00247     if (wheel)
00248     {
00249         vec2 target = wheel->GetFlatlandObject()->GetGeometry().Center() - vec2(width / 2.0f, height * 0.75f);
00250         target += scrolloffset;
00251 
00252         if (target.x < scrollbox.left) target.x = scrollbox.left;
00253         if (target.x + width > scrollbox.right) target.x = scrollbox.right - width;
00254         if (target.y < scrollbox.top) target.y = scrollbox.top;
00255         if (target.y + height > scrollbox.bottom) target.y = scrollbox.bottom - height;
00256 
00257         SetTarget(target);
00258     }
00259 }
00260 
00261 void SetPastel(Object *object)
00262 {
00263     float hue = 60;
00264     Color c(hue + (rand() % 90) - 45);
00265     object->Property().outlineColor = c;
00266     c.IncreaseBrightness(0.5);
00267     c.a = 0.9f;
00268     object->Property().fillColor = c;
00269 }
00270 
00271 void ComplexApp::Draw() const
00272 {
00273     Clear();
00274     DrawScene();
00275     Blit(helpTexture, 500-128, 300-128);
00276     Blit(boostTexture, 1000, 3425);
00277 
00278     glLoadIdentity();
00279     if (osShowCursor(OS_QUERY))
00280         Blit(pressed ? downTexture : upTexture, 2, 0, Color(1,1,1,hover ? 1 : 0.25f));
00281 }
00282 
00283 /// Load textures.
00284 void ComplexApp::InitGl()
00285 {
00286     App::InitGl();
00287 
00288     helpTexture = LoadTexture("keys.rgba");
00289     downTexture = LoadTexture("down.rgba");
00290     upTexture = LoadTexture("up.rgba");
00291     boostTexture = LoadTexture("boost.rgba");
00292     wheelTexture = LoadTexture("wheel.rgba");
00293 }
00294 
00295 /// Create the window and the OpenGL context.
00296 void ComplexApp::InitWin()
00297 {
00298     osInit(InitialWidth, InitialHeight, fullscreen ? OS_FULLSCREEN : OS_RESIZABLE, 0);
00299 }
00300 
00301 /// Reaction callback for when the wheel touches the boost icon.
00302 void ComplexApp::boostCallback(ContactList &contacts)
00303 {
00304     if (contacts.Other() != app.wheel->GetFlatlandObject())
00305         return;
00306 
00307     if (app.world.GetMotorVelocity(app.motor) < 0)
00308         app.world.SetMotorVelocity(app.motor, -0.4f);
00309     if (app.world.GetMotorVelocity(app.motor) > 0)
00310         app.world.SetMotorVelocity(app.motor, 0.4f);
00311 }
00312 
00313 /// Reaction callback for when the wheel touches the cannonball.
00314 void ComplexApp::pendulumCallback(ContactList &contacts)
00315 {
00316     if (contacts.Other() != app.wheel->GetFlatlandObject() || !app.pendulumAnchor)
00317         return;
00318 
00319     app.world.DeleteJoint(app.pendulumAnchor);
00320     app.pendulumAnchor = 0;
00321 }
00322 
00323 /// Reaction callback for when the wheel touches the bubble.
00324 void ComplexApp::bubbleCallback(ContactList &contacts)
00325 {
00326     if (contacts.Other() != app.wheel->GetFlatlandObject() || !app.bubbleAnchor)
00327         return;
00328 
00329     app.world.DeleteJoint(app.bubbleAnchor);
00330     app.bubbleAnchor = 0;
00331 
00332     Flatland::Object &front = *app.wheel->GetFlatlandObject();
00333     Flatland::Object &back = *app.wheel2->GetFlatlandObject();
00334     front.Move();
00335     back.Move();
00336     vec2 start = front.GetGeometry().Center();
00337     vec2 end = back.GetGeometry().Center();
00338     Beam *beam = new Beam(start, end, 2);
00339     beam->GetFlatlandObject()->Property().collisionMask = 0;
00340     beam->GetFlatlandObject()->SetMass(0.01f);
00341     beam->Property().outlineThickness = 0;
00342     beam->Property().fillColor = Color(0.25f, 0.35f, 0.6f, 1);
00343     beam->InsertFront(app.space);
00344 
00345     app.world.Anchor(*beam->GetFlatlandObject(), front, start, 0, 0.01f);
00346     app.world.Anchor(*beam->GetFlatlandObject(), back, end, 0, 0.01f);
00347 }
00348 
00349 /// Reaction callback to start up the block feeder motor.
00350 void ComplexApp::feederCallback(ContactList &contacts)
00351 {
00352     if (contacts.Other() != app.wheel->GetFlatlandObject() && contacts.Other() != app.wheel2->GetFlatlandObject())
00353         return;
00354 
00355     app.world.SetMotorVelocity(app.blockFeeder, 0.035f);
00356     app.world.SetMotorVelocity(app.squareWheelMotor, -0.01f);
00357 }
00358 
00359 /// Initialize the app; construct the flatland scene.
00360 ComplexApp::ComplexApp(bool full) : fullscreen(full), App(GetWidth(full), GetHeight(full))
00361 {
00362     hover = false;
00363     freeze = false;
00364     pressed = false;
00365     wheel = 0;
00366     scrollbox = aabb(-250, -100, 5000, 5000);
00367     scrolloffset = vec2(0, 0);
00368 
00369     InitWin();
00370     InitGl();
00371     InitOde();
00372 
00373     Flatland::Object::Default().friction = 40;
00374     Demo::Object::Default().outlineThickness = 1;
00375 
00376     // Create the user-controlled wheel.
00377     float radius = 27;
00378     wheel = new Wheel(vec2(400, 475), radius);
00379     wheel->SetTexture(wheelTexture);
00380     wheel->GetFlatlandObject()->Property().frictionMask = 15;
00381     wheel->GetFlatlandObject()->Property().collisionMask = ~7;
00382     wheel->Insert(space);
00383     motor = world.AddMotor(*wheel->GetFlatlandObject());
00384 
00385     // Create the back wheel.
00386     float carLength = radius * 2.5f;
00387     vec2 center(3500, 890 - carLength);
00388     wheel2 = new Wheel(center, radius);
00389     wheel2->GetFlatlandObject()->SetMass(0.01f);
00390     wheel2->GetFlatlandObject()->Property().frictionMask = 7;
00391     wheel2->GetFlatlandObject()->Property().collisionMask = ~7;
00392     wheel2->SetTexture(wheelTexture);
00393     wheel2->Insert(space);
00394     Ball *bubble = new Ball(center, carLength);
00395     bubble->Property().outlineThickness = 3;
00396     bubble->Property().fillColor = Color(1,0,0,0.1f);
00397     bubble->GetFlatlandObject()->Property().collisionMask = 4;
00398     bubble->GetFlatlandObject()->Property().friction = dInfinity;
00399     bubble->GetFlatlandObject()->Property().callback = bubbleCallback;
00400     bubble->Insert(space);
00401     bubbleAnchor = Glue(bubble, wheel2);
00402 
00403     // Set up some colors for the terrains.
00404     Demo::Object::Default().outlineColor = Color::White;
00405     Demo::Object::Default().fillColor = Color(106/255.0f, 160/255.0f, 248/255.0f, 1);
00406     Demo::Object::Default().altFillColor = Color::White;
00407 
00408     // Northwest curl and ceiling
00409     Terrain *t = new Terrain(vec2(-250, 400), -100);
00410     for (float theta = 175; theta >= 0; theta -= 5)
00411         t->Add(vec2(50, 400) + vec2(300, 0).rotate(theta));
00412     t->Add(vec2(1000, 400));
00413     for (float theta = 230; theta <= 270; theta += 10)
00414         t->Add(vec2(1500, 750) + vec2(50, 0).rotate(theta));
00415     t->Add(vec2(2000, 800));
00416     for (float theta = 270; theta < 320; theta += 10)
00417         t->Add(vec2(2018, 750) + vec2(50, 0).rotate(theta));
00418     t->Add(vec2(2500, 400));
00419     t->Add(vec2(4100, 400));
00420     t->GetFlatlandObject()->Property().friction = dInfinity;
00421     t->Insert(space);
00422 
00423     // Starting terrain, with a rounded west edge
00424     t = new Terrain(vec2(0, 590), 1100);
00425     t->Add(vec2(950, 590));
00426     for (float theta = 80; theta >= 0; theta -= 10)
00427         t->Add(vec2(950, 640) + vec2(50, 0).rotate(theta));
00428     t->Insert(space);
00429     t->InsertEastBorder(space);
00430     space << new Line(vec2(1000, 900), vec2(1000, 3000));
00431 
00432     t = new Terrain(vec2(1000, 890), 1100);
00433     t->Add(vec2(1500, 890));
00434     t->Insert(space);
00435 
00436     t = new Terrain(vec2(2000, 890), 1100);
00437     t->Add(vec2(4000, 890));
00438     t->Insert(space);
00439     t->GetFlatlandObject()->Property().collisionMask = ~3;
00440 
00441     // Hang a rope between the two previous terrains.
00442     {
00443         Flatland::Object::PushProperties();
00444         Flatland::Object::Default().frictionMask = 7;
00445         vec2 start = vec2(1500, 890);
00446         vec2 end = vec2(2000, 890);
00447         float slack = 40;
00448         float length = end.x - start.x + slack;
00449         float tautness = 20000;
00450         float bottom = 1100;
00451         Rope *r = new Rope(start, end, length, tautness);
00452         r->Terrainify(bottom);
00453         r->Insert(space);
00454         Anchor(r->front(), start);
00455         Anchor(r->back(), end);
00456         Flatland::Object::PopProperties();
00457     }
00458 
00459     // Pendulum.
00460     {
00461         Flatland::Object::PushProperties();
00462         Object::PushProperties();
00463 
00464         Flatland::Object::Default().collisionMask = 3;
00465         Object::Default().fillColor = Color(0,0,0,1);
00466         Object::Default().outlineColor = Color(0.5f,0.7f,1,1);
00467         Object::Default().outlineThickness = 4;
00468 
00469         vec2 start = vec2(2720, 700);
00470         vec2 end = vec2(2670, 820);
00471         float thickness = 5;
00472         Beam *tether = new Beam(start, end, thickness);
00473         tether->Insert(space);
00474 
00475         float radius = 20;
00476         end = end + (end - start).hat() * radius;
00477         Flatland::Circle *cannonball = new Flatland::Circle(end, radius);
00478         tether->Add(cannonball);
00479 
00480         tether->GetFlatlandObject()->Property().callback = pendulumCallback;
00481         tether->GetFlatlandObject()->SetMass(100);
00482         tether->GetFlatlandObject()->Property().frictionMask = 0;
00483 
00484         Anchor(tether, start);
00485         pendulumAnchor = Anchor(tether, end);
00486 
00487         Flatland::Object::PopProperties();
00488         Object::PopProperties();
00489     }
00490 
00491     // Dominos
00492     for (int i = 0; i < 20; ++i)
00493     {
00494         Block *block = new Block(vec2(2750 + i * 30.0f, 890 - 15), 10, 30);
00495         Color c(60.0f + (rand() % 90) - 45);
00496         block->Property().outlineColor = c;
00497         c.IncreaseBrightness(0.5);
00498         c.a = 0.9f;
00499         block->Property().fillColor = c;
00500         block->GetFlatlandObject()->SetMass(40);
00501         block->GetFlatlandObject()->Property().frictionMask = 1 + i % 2;
00502         block->Insert(space);
00503     }
00504 
00505     // Catapult
00506     {
00507         vec2 center(1150, 750);
00508         float width = 200;
00509         float height = 5;
00510         vec2 hinge(center.x - width / 4, center.y);
00511         Catapult *c = new Catapult(center, width, height, hinge);
00512         c->Rotate(-22);
00513         c->Insert(space);
00514         c->InsertSouthEastAnchor(space);
00515 
00516         center += vec2(90, -50);
00517         Block *b = new Block(center, 10, 10);
00518         b->GetFlatlandObject()->SetMass(0.5);
00519         b->GetFlatlandObject()->Property().friction = dInfinity;
00520         b->Property().fillColor = Color::PaleYellow;
00521         b->Property().outlineColor = Color::PaleYellow;
00522         b->Insert(space);
00523 
00524         center.x -= 14;
00525         b = new Block(center, 10, 10);
00526         b->GetFlatlandObject()->SetMass(0.5);
00527         b->GetFlatlandObject()->Property().friction = dInfinity;
00528         b->Property().fillColor = Color::PaleYellow;
00529         b->Property().outlineColor = Color::PaleYellow;
00530         b->Insert(space);
00531     }
00532 
00533     // Block feeder blocks
00534     {
00535         Flatland::Object::PushProperties();
00536         Flatland::Object::Default().frictionMask = 1;
00537         Flatland::Object::Default().friction = 1;
00538         Flatland::Object::Default().density = 0.1f;
00539         float width = 90;
00540         float height = 50;
00541         Block *buffer1 = new Block(vec2(4050, 1300), width, height);
00542         SetPastel(buffer1);
00543         buffer1->Insert(space);
00544         Block *buffer2 = new Block(vec2(4050, 1000), width, height);
00545         SetPastel(buffer2);
00546         buffer2->Insert(space);
00547         Flatland::Object::PopProperties();
00548 
00549         buffer2->GetFlatlandObject()->Property().callback = feederCallback;
00550 
00551         Line *l = new Line(vec2(4000, 890), vec2(4000, 1620));
00552         l->GetFlatlandObject()->Property().frictionMask = 2;
00553         l->Insert(space);
00554     }
00555 
00556     // Roulette for square wheel, defined as the catenary y = -cosh(x) truncated by x = +/- asinh(1)
00557     t = 0;
00558     float dx = 5;
00559     float asinh1 = .881373587019543f;
00560     float xx = -asinh1;
00561     for (float x = 3000 + dx; x <= 4000; x += dx)
00562     {
00563         float y = 1570 + 50 * cosh(xx);
00564         if (!t)
00565             t = new Terrain(vec2(0, y), 1100);
00566         else
00567             t->Add(vec2(x, y));
00568         xx += 2 * asinh1 / 15;
00569         if (xx > asinh1)
00570             xx = -asinh1;
00571     }
00572     t->Insert(space);
00573 
00574     Block *b = new Block(vec2(3923, 1500), 92, 92);
00575     b->Property().fillColor = Color::Black;
00576     b->Insert(space);
00577     b->GetFlatlandObject()->Property().friction = dInfinity;
00578     squareWheelMotor = world.AddMotor(*b->GetFlatlandObject());
00579 
00580     // West block
00581     t = new Terrain(vec2(0, 590 - 100), 595, true, false);
00582     t->Add(vec2(20, 590 - 100));
00583     t->Property().altFillColor = t->Property().fillColor;
00584     t->Insert(space);
00585 
00586     t = new Terrain(vec2(1500, 2850), 2850);
00587     for (float x = 1510; x <= 4100; x += 10)
00588     {
00589         float y = 2500 - log10f((x - 1400) / 270) * 800;
00590         t->Add(vec2(x, y));
00591     }
00592     t->Insert(space);
00593 
00594     space << new Line(vec2(1000, 3000), vec2(1750, 3000));
00595     space << new Line(vec2(2500, 3000), vec2(3000, 3000));
00596 
00597     // Rope
00598     {
00599         Flatland::Object::PushProperties();
00600         Flatland::Object::Default().friction = dInfinity;
00601         Flatland::Object::Default().frictionMask = 7;
00602         Flatland::Object::Default().density = 5;
00603         vec2 start = vec2(1750, 3000);
00604         vec2 end = vec2(2500, 3000);
00605         float slack = 40;
00606         float length = end.x - start.x + slack;
00607         float tautness = 20000;
00608         Rope *r = new Rope(start, end, length, tautness);
00609         r->Property().outlineColor = Color::Red;
00610         r->Property().outlineThickness = 3;
00611         r->Insert(space);
00612         Anchor(r->front(), start);
00613         Anchor(r->back(), end);
00614         Flatland::Object::PopProperties();
00615     }
00616 
00617     // Southernmost, easternmost, westernmost terrain
00618     t = new Terrain(vec2(-250, 400), 5000);
00619     for (float x = 0.5f + 0.1f; x < 10; x += 0.1f)
00620     {
00621         float y = 5 / x;
00622         vec2 v;
00623         v.y = (y - 0.5f) / 9.5f;
00624         v.y = 1 - v.y;
00625         v.y = v.y * (3500 - 400) + 400;
00626         v.x = (x - 0.5f) / 9.5f;
00627         v.x = v.x * (1000 - -250) + -250;
00628         t->Add(v);
00629     }
00630     t->Add(vec2(1000, 3500));
00631     float dtheta = pi / 50;
00632     for (float theta = dtheta; theta < pi; theta += dtheta)
00633         t->Add(vec2(1000 + theta * 1500 / pi, 4000 + 500 * cosf(pi - theta)));
00634     t->Add(vec2(2500, 4500));
00635     t->Add(vec2(4050, 4500));
00636     for (float theta = -90 + 10; theta < 0; theta += 10)
00637         t->Add(vec2(4075, 4475) + vec2(25, 0).rotate(theta));
00638     t->Add(vec2(4100, -100));
00639     t->Add(vec2(5000, -100));
00640     t->GetFlatlandObject()->Property().friction = dInfinity;
00641     t->GetFlatlandObject()->Property().collisionMask = ~8;
00642     t->GetFlatlandObject()->Property().frictionMask = 4;
00643     t->Insert(space);
00644 
00645     // Speed boost
00646     Point *boost = new Point(vec2(1000 + 32, 3425 + 32));
00647     boost->GetFlatlandObject()->Property().callback = boostCallback;
00648     boost->GetFlatlandObject()->Property().collisionMask = 0;
00649     boost->Insert(space);
00650     Anchor(boost, vec2(1000 + 32, 3425 + 32));
00651 
00652     // Block feeder
00653     {
00654         Object::PushProperties();
00655         Object::Default().fillColor = Color::PaleRed;
00656         Object::Default().outlineColor = Color::Black;
00657         Object::Default().outlineThickness = 2;
00658 
00659         vec2 start(4300, 1670);
00660         vec2 end(4600, 1500);
00661         float length = 130;
00662 
00663         start -= vec2(170, 0);
00664         end -= vec2(170, 0);
00665 
00666         // Motor
00667         Wheel *w = new Wheel(end, 100);
00668         w->Insert(space);
00669         w->GetFlatlandObject()->Property().collisionMask = 0;
00670         Anchor(w, w->GetFlatlandObject()->GetGeometry().Center());
00671         blockFeeder = world.AddMotor(*w->GetFlatlandObject());
00672 
00673         Object::Default().outlineThickness = 4;
00674 
00675         // Pusher
00676         Beam *pusher = new Beam(start - vec2(length, 0), start, 50);
00677         pusher->GetFlatlandObject()->Property().collisionMask = 8;
00678         pusher->Insert(space);
00679         AnchorAxis(pusher, vec2(1, 0));
00680 
00681         // Transmission.
00682         end -= vec2(60, 0);
00683         Beam *transmission = new Beam(start, end, 20);
00684         transmission->Insert(space);
00685         transmission->GetFlatlandObject()->Property().collisionMask = 0;
00686         Anchor(transmission, w, end);
00687         Anchor(transmission, pusher, start);
00688 
00689         Object::PopProperties();
00690     }
00691 }

Generated on Sat Jan 13 17:20:21 2007 for Flatland by doxygen 1.5.1