/* The constructor initializes the data structures and loads the necessary ones with recyclable objects for collision tests. */ Physics::Physics() { // DEFAULT GRAVITY IS 1.0f gravity = DEFAULT_GRAVITY; // POPULATE THEM WITH 1000 OBJECTS TO SHARE // WHY 1000? BECAUSE I HAD TO PICK SOME NUMBER BIG ENOUGH // THAT WE'LL NEVER REACH, NOT THE MOST EFFICIENT TECHNIQUE, // BUT WE CAN CUSTOMIZE IT VIA A BUDGET IF WE KNEW WHAT // THE GAME'S NEEDS ARE for (int i = 0; i < 1000; i++) { // THESE ARE DUMMY OBJECTS USED FOR TILES, SINCE // TILES DON'T KNOW THEIR OWN LOCATIONS CollidableObject *co = new CollidableObject(); co->setCurrentlyCollidable(true); co->getPhysicalProperties()->setVelocity(0.0f, 0.0f); recycledCollidableObjectsList.push_back(co); // THESE ARE ALL THE COLLISIONS WE'LL USE Collision *c = new Collision(); recycledCollisions.push_back(c); } // NOW MAKE THE SWEEP AND PRUNE VECTORS. AGAIN, THESE GUYS KEEP ALL // SPRITE OBJECTS SORTED BY LEFT AND RIGHT SWEPT SHAPE EDGES SUCH THAT // WE MAY EASILY TEST FOR NEIGHBOR TO NEIGHBOR SPRITE COLLISIONS RATHER // THAN DO SOME CRAZY N! COMPUTATION sortedSweptShapes[LEFT_EDGE] = new vector<CollidableObject*>(); sortedSweptShapes[RIGHT_EDGE] = new vector<CollidableObject*>(); }
/* Moves all sprites ahead per their current velocities using the timeStep variable. */ void Physics::moveAllSpritesUpByTimeStep(float timeStep) { // GO THROUGH ALL THE SPRITES vector<CollidableObject*>::iterator spritesIt = sortedSweptShapes[LEFT_EDGE]->begin(); while (spritesIt != sortedSweptShapes[LEFT_EDGE]->end()) { if ((timeStep > 0.0f) && ((timeStep + currentCollisionTime) <= 1.0f)) { CollidableObject *sprite = *spritesIt; // SCALE THEIR VELOCITIES USING THE TIME STEP float incX = sprite->getPhysicalProperties()->getVelocityX() * timeStep; float incY = sprite->getPhysicalProperties()->getVelocityY() * timeStep; float distance = sqrt((incX * incX) + (incY * incY)); // AND MOVE THEM sprite->getBoundingVolume()->incCenterX(incX); sprite->getBoundingVolume()->incCenterY(incY); // MAKE SURE THEY GET RENDERED WHERE WE JUST MOVED THEM ((AnimatedSprite*)sprite)->correctToTightBoundingVolume(); } // AND GO TO THE NEXT SPRITE spritesIt++; } }
/* Default constructor, it initializes all data using default values. */ Physics::Physics() { maxVelocity = DEFAULT_MAX_VELOCITY; gravity = DEFAULT_GRAVITY; /*for(int i = 0; i < 1000; i++) { Collision *c = new Collision(); collisionStack.push(c); }//end for*/ for(int i = 0; i < 1000; i++) { Collision *c = new Collision(); collisionStack[i] = c; if(i < 500) { CollidableObject* co = new CollidableObject(); co->setCurrentlyCollidable(true); co->setIsStatic(true); PhysicalProperties* pp = co->getPhysicalProperties(); pp->setVelocity(0,0); coStack[i] = co; } }//end for collisionStackCounter = 999; coStackCounter = 499; }
Physics::Physics() { b2Vec2 Boxgravity(0.0f, -200.0f); world = new b2World(Boxgravity); for (int i = 0; i < 1000; i++) { // THESE ARE DUMMY OBJECTS USED FOR TILES, SINCE // TILES DON'T KNOW THEIR OWN LOCATIONS CollidableObject *co = new CollidableObject(); co->setCurrentlyCollidable(true); co->getPhysicalProperties()->setVelocity(0.0f, 0.0f); recycledCollidableObjectsList.push_back(co); // THESE ARE ALL THE COLLISIONS WE'LL USE Collision *c = new Collision(); recycledCollisions.push_back(c); } // NOW MAKE THE SWEEP AND PRUNE VECTORS. AGAIN, THESE GUYS KEEP ALL // SPRITE OBJECTS SORTED BY LEFT AND RIGHT SWEPT SHAPE EDGES SUCH THAT // WE MAY EASILY TEST FOR NEIGHBOR TO NEIGHBOR SPRITE COLLISIONS RATHER // THAN DO SOME CRAZY N! COMPUTATION sortedSweptShapes[LEFT_EDGE] = new vector<CollidableObject*>(); sortedSweptShapes[RIGHT_EDGE] = new vector<CollidableObject*>(); }
void Physics::updateSweptShapeIndices(vector<CollidableObject*> *sweptShapes, unsigned int ordering) { vector<CollidableObject*>::iterator it = sweptShapes->begin(); unsigned int counter = 0; while (it != sweptShapes->end()) { CollidableObject *co = (*it); co->setSweepAndPruneIndex(ordering, counter); counter++; it++; } }
/* Called when a collision is detected between a world tile and a sprite, this records that collision so that it can be resolved later if needed. */ void Physics::addTileCollision(CollidableObject *dynamicObject, Tile *tile, float tileX, float tileY, float tileWidth, float tileHeight) { // IF WE'VE ALREADY HANDLED A COLLISION BETWEEN THESE TWO OBJECTS THIS // FRAME THEN IGNORE IT set<Tile*> doTiles = spriteToTileCollisionsThisFrame[dynamicObject]; if (doTiles.find(tile) != doTiles.end()) return; // GET A DUMMY COLLIABLE OBJECT TO USE FOR THE TILE CollidableObject *tileInfoForCollision = recycledCollidableObjectsList.back(); // FILL IT WITH DATA AABB *bv = tileInfoForCollision->getBoundingVolume(); bv->setCenterX(tileX + (tileWidth/2)); bv->setCenterY(tileY + (tileHeight/2)); bv->setWidth(tileWidth); bv->setHeight(tileHeight); // FIRST WE'RE GOING TO DO A MORE NARROW CHECK TO SEE IF THE dynamicObject // REALLY DOES COLLIDE WITH THE TILE. TO DO SO WE'LL CALCULATE THE TIME // OF COLLISION. IF IT HAPPENS AFTER THIS FRAME IS OVER (> 1), THEN WE // WILL IGNORE IT unsigned int co1Edge, co2Edge; float timeUntilCollision = calculateTimeUntilCollision(dynamicObject, tileInfoForCollision, co1Edge, co2Edge, 0.0f); if (timeUntilCollision > 1.0f) return; // IF IT MADE IT HERE, A COLLISION IS HAPPENING // AND REMOVE IT FROM THE RECYCLING CENTER recycledCollidableObjectsList.pop_back(); // NOW LET'S MAKE A COLLISION FOR THE TILE-SPRITE Collision *collisionToAdd = recycledCollisions.back(); collisionToAdd->setCO1(dynamicObject); collisionToAdd->setCO2(tileInfoForCollision); collisionToAdd->setCO1Edge(co1Edge); collisionToAdd->setCO2Edge(co2Edge); collisionToAdd->setCollisionWithTile(true); collisionToAdd->setTimeOfCollision(timeUntilCollision); collisionToAdd->setTile(tile); recycledCollisions.pop_back(); activeCollisions.push_back(collisionToAdd); }
CollidableObject * CollidableObject::CreateRectangle(Vector2 position, Vector2 size) { CollidableObject *pRectangle = new CollidableObject(); pRectangle->SetPosition(position + (size * 0.5)); pRectangle->GetVertices()->push_back(position - pRectangle->GetPosition()); pRectangle->GetVertices()->push_back(Vector2(position.GetX(), position.GetY() + size.GetY()) - pRectangle->GetPosition()); pRectangle->GetVertices()->push_back(position + size - pRectangle->GetPosition()); pRectangle->GetVertices()->push_back(Vector2(position.GetX() + size.GetX(), position.GetY()) - pRectangle->GetPosition()); pRectangle->GetNormals()->push_back(Vector2(1, 0)); pRectangle->GetNormals()->push_back(Vector2(0, 1)); return pRectangle; }
void BugginOutCollisionListener::respondToCollision(Game *game, Collision *collision) { // NOTE FROM THE COLLIDABLE OBJECTS, WHICH ARE IN THE COLLISION, // WE CAN CHECK AND SEE ON WHICH SIDE THE COLLISION HAPPENED AND // CHANGE SOME APPROPRIATE STATE ACCORDINGLY if (!collision->isCollisionWithTile()) { CollidableObject *sprite = collision->getCO1(); if (sprite->getCollisionEdge() == BOTTOM_EDGE) { // ENEMY IS DEAD - WE SHOULD PLAY A DEATH ANIMATION // AND MARK IT FOR REMOVAL } else { // PLAYER IS DEAD - WE SHOULD PLAY A DEATH ANIMATION // AND MARK IT FOR REMOVAL/RESPAWN/RESTART GAME, WHATEVER // THE DEMANDS OF THE GAME ARE } } }
/* This method makes sure the co sprite is in its proper sorted location in the ordering sweep and prune data structure (i.e. the one for LEFT_EDGE, RIGHT_EDGE, etc.), looking only in either the increasing or decreasing direction (according to the bool argument). */ void Physics::reorderSweptShape(CollidableObject *co, unsigned int ordering, bool increasingDirection) { // HERE WE'LL MAKE SURE THIS COLLIDABLE // OBJECT IS IN IT'S PROPER PLACE IN THE SWEPT SHAPE // DATA STRUCTURE SPECIFIED BY ORDERING IN EITHER THE // INCREASING OR DECREASING DIRECTION vector<CollidableObject*> *sweptShapes = sortedSweptShapes[ordering]; // FIRST ON THE LEFT-EDGE SORTED VECTOR unsigned int coIndex = co->getSweepAndPruneIndex(ordering); unsigned int testIndex = coIndex - 1; unsigned int limitIndex = 0; if (increasingDirection) { testIndex = coIndex + 1; limitIndex = sweptShapes->size() - 1; } CollidableObject *temp; if ((0 <= testIndex) && (testIndex <= sweptShapes->size() - 1)) { bool limitReached = false; // MOVE IT UP OR DOWN THE DATA STRUCTURE AS FAR AS IT NEEDS TO GO while (!limitReached) { CollidableObject *testCO = sweptShapes->at(testIndex); float coSide = getSide(co, ordering); float testSide = getSide(testCO, ordering); if (increasingDirection) { if (coSide < testSide) limitReached = true; else { temp = testCO; (*sweptShapes)[testIndex] = co; (*sweptShapes)[coIndex] = temp; co->setSweepAndPruneIndex(ordering, testIndex); temp->setSweepAndPruneIndex(ordering, coIndex); testIndex++; coIndex++; if (coIndex == (sweptShapes->size()-1)) limitReached = true; } } else { if (coSide > testSide) limitReached = true; else { temp = testCO; (*sweptShapes)[testIndex] = co; (*sweptShapes)[coIndex] = temp; co->setSweepAndPruneIndex(ordering, testIndex); temp->setSweepAndPruneIndex(ordering, coIndex); testIndex--; coIndex--; if (coIndex == 0) limitReached = true; } } } } }
/* This is where all game physics starts each frame. It is called each frame by the game statem manager after player input and AI have been processed. It updates the physical state of all dynamic objects in the game and moves all objects to their end of frame positions, updates all necessary object velocities, and calls all collision event handlers. */ void Physics::update(Game *game) { // WE'LL USE A CONTINUOUS COLLISION SYSTEM TO ENSURE TEMPORAL // COHERENCE, WHICH MEANS WE'LL MAKE SURE COLLISIONS ARE RESOLVED // IN THE ORDER WITH WHICH THEY HAPPEN. WE DON'T WANT GAME EVENTS // TO APPEAR TO HAPPEN IN THE WRONG ORDER. WE'LL TRY TO MAKE IT // A LITTLE MORE EFFICIENT BY EMPLOYING A VARIATION ON THE // SWEEP AND PRUNE ALGORITHM FOR DYNAMIC-DYNAMIC OBJECT COLLISIONS // IN CASE WE'RE DOING THE ONE UPDATE STEP AT A TIME // THIS MAKES SURE THE UPDATE DOESN'T GET CALLED AGAIN // NEXT FRAME WITHOUT THE USER EXPLICITY REQUESTING IT // BY PRESSING THE 'T' KEY (for Time sTep) activatedForSingleUpdate = false; // WE'LL NEED THE WORLD TO ACCESS THE SPRITES AND WORLD LAYERS GameStateManager *gsm = game->getGSM(); World *world = gsm->getWorld(); // NOTE THAT WE MAKE SURE THE activeCollisions VECTOR IS // EMPTIED BEFORE THIS METHOD EXITS, SO WE CAN ASSUME // IT'S EMPTY NOW. activeCollisions CONTAINS ALL THE COLLISIONS // DETECTED SO FAR THIS FRAME. THESE ARE THE THINGS WE MUST // RESOLVE. // START THE CLOCK AT 0, THAT MEANS 0% OF THE WAY THROUGH THE FRAME. // NOTE THAT TIME 0 IS THE MOST DANGEROUS TIME FOR DETECTING COLLISIONS // BECAUSE THEY CAN BE EASILY OVERLOOKED. THE SAME FOR SIMULTANEOUS // COLLISIONS. TO MINIMIZE RIGID BODY PENETRATION, SUCH CIRCUMSTANCES // ARE TYPICALLY HANDLED AS SPECIAL CASES currentCollisionTime = 0.0f; // FIRST WE NEED TO DO COLLISION TESTING PREP WORK FOR SPRITES // APPLY ACCELERATION AND GRAVITY TO VELOCITY // INIT TILE COLLISION INFO // SET ON TILE LAST FRAME USING ON TILE THIS FRAME // SET ON TILE THIS FRAME TO FALSE // GET COLLISIONS WITH ALL TILES TO HAPPEN DURING THIS FRAME // PUT THESE COLLISIONS INTO A SORTABLE DATA STRUCTURE // INIT SPRITE'S SWEPT SHAPE INFO // FOR ALL SPRITES, INCLUDING THE BOTS AND PLAYER vector<CollidableObject*>::iterator spritesIt = sortedSweptShapes[LEFT_EDGE]->begin(); while (spritesIt != sortedSweptShapes[LEFT_EDGE]->end()) { CollidableObject *sprite = (*spritesIt); prepSpriteForCollisionTesting(world, sprite); getAllTileCollisionsForAGivenSprite(world, sprite, 1.0f); spritesIt++; } // PREPARE FOR SPRITE-SPRITE COLLISION TESTING // SWEEP AND PRUNE DATA STRUCTURES PREP WORK // SORT S_AND_P VECTOR SORTED BY START X OF SWEPT SHAPE // SORT S_AND_P VECTOR SORTED BY END X OF SWEPT SHAPE // WE DON'T NEED THE Y-AXIS SORTED, BUT WOULD IF THIS // WERE A 3D SYSTEM TO SAVE ON COMPARISONS. // WE'RE USING C++'s STL sort METHOD AND ARE PROVIDING // A CUSTOM MEANS FOR COMPARISON sort(sortedSweptShapes[LEFT_EDGE]->begin(), sortedSweptShapes[LEFT_EDGE]->end(), SweptShapesComparitorByLeft()); sort(sortedSweptShapes[RIGHT_EDGE]->begin(), sortedSweptShapes[RIGHT_EDGE]->end(), SweptShapesComparitorByRight()); // RECORD SORTED POSITIONS WITH EACH SPRITE. THEY NEED TO KNOW WHERE // THEY ARE IN THOSE DATA STRUCTURES SUCH THAT WE CAN JUMP INTO // THOSE DATA STRUCTURES TO TEST COLLISIONS WITH NEIGHBORS updateSweptShapeIndices(); // YOU'LL NEED TO TEST FOR SPRITE-TO-SPRITE COLLISIONS HERE // *** LOOP STARTS HERE. WE'LL DO THIS UNTIL THERE ARE NO // MORE COLLISIONS TO RESOLVE FOR THIS FRAME while (activeCollisions.size() > 0) { // SORT COLLISION OBJECTS BY TIME OF COLLISION // NOTE THAT I'M JUST EMPLOYING THE STL'S List // CLASS' SORT METHOD BY PROVIDING MY OWN // MEANS FOR COMPARING Collision OBJECTS activeCollisions.sort(CollisionComparitor()); // GET FIRST COLLISION - NOTE THAT WE HAVE THE COLLISIONS SORTED // IN DESCENDING ORDER, SO TO TAKE THE EARLIEST ONE, WE REMOVE IT // FOM THE BACK OF THE SORTED LIST Collision *earliestCollision = activeCollisions.back(); activeCollisions.pop_back(); float collisionTime = earliestCollision->getTimeOfCollision(); // MOVE ALL SPRITES UP TO TIME OF FIRST COLLISION USING // APPROPRIATELY SCALED VELOCITIES moveAllSpritesUpToBufferedTimeOfCollision(earliestCollision); // AND ADVANCE COLLISION TIME currentCollisionTime = collisionTime; // AND UPDATE THE VELOCITIES OF THE SPRITE(S) INVOLVED IN THE COLLISION performCollisionResponse(earliestCollision); // EXECUTE COLLISION EVENT CODE // TEST TO SEE TYPES OF OBJECTS AND APPROPRIATE RESPONSE // ACCORDING TO CUSTOMIZED COLLISION EVENT HANDLER collisionListener->respondToCollision(game, earliestCollision); // FOR THE TWO OBJECTS INVOLVED IN THE COLLISION // REMOVE ALL OTHER COLLISIONS INVOLVING THEM // SINCE THEY ARE NOW OBSOLETE. THE REASON BEING // THE OBJECT COLLISION NOW LIKELY HAS A // DIFFERENT VECTOR // UPDATE THEIR SWEPT SHAPES // TEST THEM AGAINST TILES AGAIN CollidableObject *co1 = earliestCollision->getCO1(); CollidableObject *co2 = earliestCollision->getCO2(); removeActiveCOCollisions(co1); co1->updateSweptShape(1.0f - currentCollisionTime); getAllTileCollisionsForAGivenSprite(world, co1, 1.0f - currentCollisionTime); // ONLY DO IT FOR THE SECOND ONE IF IT'S NOT A TILE if (!earliestCollision->isCollisionWithTile()) { removeActiveCOCollisions(co2); co2->updateSweptShape(1.0f - currentCollisionTime); getAllTileCollisionsForAGivenSprite(world, co2, 1.0f - currentCollisionTime); } else { spriteToTileCollisionsThisFrame[co1].insert(earliestCollision->getTile()); recycledCollidableObjectsList.push_back(co2); } // NOW WE NEED TO SEE IF THE SPRITES INVOLVED IN THE JUST // RESOLVED COLLISION ARE GOING TO BE INVOLVED IN ANY MORE // WITH OTHER SPRITES BUT WE DON'T WANT TO CHECK ALL OF THEM, // WE ONLY WANT TO CHECK NEIGHBORS, BUT FIRST WE HAVE TO // MAKE SURE THE SPRITE(S) THAT WE JUST RESOLVED ARE IN THEIR // PROPER SWEPT SHAPE LOCATIONS WITHOUT HAVING TO RESORT EVERTYHING // IF IT WAS ONLY ONE SPRITE WITH A TILE THIS IS EASY TO DO if (earliestCollision->isCollisionWithTile()) { reorderCollidableObject(co1); } // YOU'LL HAVE TO WORRY ABOUT REORDERING STUFF FOR COLLISIONS // BETWEEN TWO SPRITES // NOW TEST NEIGHBORS OF SPRITES INVOLVED IN RESOLVED COLLISION // AGAINST NEIGHBORS IN SWEPT SHAPE DATA STRUCTURES. YOU'LL HAVE // TO FIGURE OUT HOW TO DO THIS AND HOW TO RESOLVE SUCH COLLISIONS // RECYCLE THE COLLISION SINCE WE'RE NOW DONE WITH IT recycledCollisions.push_back(earliestCollision); } // APPLY THE REMAINING TIME TO MOVE THE SPRITES. NOTE THAT // THIS IS ACTUALLY A VERY RISKY, TRICKY STEP BECAUSE IT COULD // MOVE OBJECTS ALMOST TO THE POINT OF COLLISION, WHICH MAY THEN // BE DETECTED ALMOST AT TIME 0 NEXT FRAME. THERE ARE OTHER TRICKY // ISSUES RELATED TO OUR BUFFER AS WELL, SO WE CHEAT A LITTLE HERE // AND SCALE THE TIME REMAINING DOWN A LITTE if (currentCollisionTime < 1.0f) moveAllSpritesToEndOfFrame(); // INIT TILE COLLISION INFO // SET ON TILE LAST FRAME USING ON TILE THIS FRAME // SET ON TILE THIS FRAME TO FALSE spritesIt = sortedSweptShapes[LEFT_EDGE]->begin(); while (spritesIt != sortedSweptShapes[LEFT_EDGE]->end()) { CollidableObject *sprite = (*spritesIt); sprite->advanceOnTileStatus(); spritesIt++; } // WE'RE NOT GOING TO ALLOW MULTIPLE COLLISIONS TO HAPPEN IN A FRAME // BETWEEN THE SAME TWO OBJECTS spriteToTileCollisionsThisFrame.clear(); }
void BalloonEscapeCollisionListener::respondToCollision(Game *game, Collision *collision) { // NOTE FROM THE COLLIDABLE OBJECTS, WHICH ARE IN THE COLLISION, // WE CAN CHECK AND SEE ON WHICH SIDE THE COLLISION HAPPENED AND // CHANGE SOME APPROPRIATE STATE ACCORDINGLY GameStateManager *gsm = game->getGSM(); AnimatedSprite *player = gsm->getSpriteManager()->getPlayer(); PhysicalProperties *pp = player->getPhysicalProperties(); //AnimatedSprite *bot = collision CollidableObject *sprite2 = collision->getCO2(); PhysicalProperties *pp2 = sprite2->getPhysicalProperties(); AnimatedSprite *bot = (AnimatedSprite*)sprite2; if (!collision->isCollisionWithTile() && player->getCurrentState() != L"DYING") { CollidableObject *sprite = collision->getCO1(); if (sprite2->getPhysicalProperties()->getZ() == 1.0f) { bot = (AnimatedSprite*)sprite; pp = sprite2->getPhysicalProperties(); pp2 = sprite->getPhysicalProperties(); sprite = collision->getCO2(); sprite2 = collision->getCO1(); if (sprite->getCollisionEdge() == BOTTOM_EDGE) { bot->setCurrentState(L"DYING"); pp2->setVelocity(0.0f, 0.0f); pp2->setAccelerationX(0); pp2->setAccelerationY(0); // ENEMY IS DEAD - WE SHOULD PLAY A DEATH ANIMATION // AND MARK IT FOR REMOVAL } else if (bot->getCurrentState() != L"DYING") { if (pp->getDelay() == 0) { if (pp->getHP() == 10 ) { //lives->setCurrentState(L"TWO"); if(deadonce == true) //lives->setCurrentState(L"ONE"); player->setCurrentState(L"DYING"); pp->setDelay(90); pp->setVelocity(0.0f, 0.0f); pp->setAccelerationX(0); pp->setAccelerationY(0); deadonce=true; } else { pp->setDelay(90); pp->setHP(pp->getHP()-10); SpriteManager *spriteManager = gsm->getSpriteManager(); AnimatedSpriteType *yellowman = spriteManager->getSpriteType(3); player->setSpriteType(yellowman); } } // PLAYER IS DEAD - WE SHOULD PLAY A DEATH ANIMATION // AND MARK IT FOR REMOVAL/RESPAWN/RESTART GAME, WHATEVER // THE DEMANDS OF THE GAME ARE } } else if(sprite->getPhysicalProperties()->getZ() == 1.0f) { PhysicalProperties *pp = sprite->getPhysicalProperties(); if (sprite->getCollisionEdge() == BOTTOM_EDGE) { bot->setCurrentState(L"DYING"); pp2->setVelocity(0.0f, 0.0f); pp2->setAccelerationX(0); pp2->setAccelerationY(0); // ENEMY IS DEAD - WE SHOULD PLAY A DEATH ANIMATION // AND MARK IT FOR REMOVAL } else if (bot->getCurrentState() != L"DYING") { if (pp->getDelay() == 0) { if (pp->getHP() == 10 ) { //lives->setCurrentState(L"TWO"); if(deadonce == true) //lives->setCurrentState(L"ONE"); player->setCurrentState(L"DYING"); pp->setDelay(90); pp->setVelocity(0.0f, 0.0f); pp->setAccelerationX(0); pp->setAccelerationY(0); deadonce=true; } else { pp->setDelay(90); pp->setHP(pp->getHP()-10); SpriteManager *spriteManager = gsm->getSpriteManager(); AnimatedSpriteType *yellowman = spriteManager->getSpriteType(3); player->setSpriteType(yellowman); } } // PLAYER IS DEAD - WE SHOULD PLAY A DEATH ANIMATION // AND MARK IT FOR REMOVAL/RESPAWN/RESTART GAME, WHATEVER // THE DEMANDS OF THE GAME ARE } } } if (pp->getDelay() == 0) { SpriteManager *spriteManager = gsm->getSpriteManager(); AnimatedSpriteType *redman = spriteManager->getSpriteType(2); player->setSpriteType(redman); } }
/* This is where all game physics starts each frame. It is called each frame by the game statem manager after player input and AI have been processed. It updates the physical state of all dynamic objects in the game and moves all objects to their end of frame positions, updates all necessary object velocities, and calls all collision event handlers. */ void Physics::update(Game *game) { // WE'LL USE A CONTINUOUS COLLISION SYSTEM TO ENSURE TEMPORAL // COHERENCE, WHICH MEANS WE'LL MAKE SURE COLLISIONS ARE RESOLVED // IN THE ORDER WITH WHICH THEY HAPPEN. WE DON'T WANT GAME EVENTS // TO APPEAR TO HAPPEN IN THE WRONG ORDER. WE'LL TRY TO MAKE IT // A LITTLE MORE EFFICIENT BY EMPLOYING A VARIATION ON THE // SWEEP AND PRUNE ALGORITHM FOR DYNAMIC-DYNAMIC OBJECT COLLISIONS // IN CASE WE'RE DOING THE ONE UPDATE STEP AT A TIME // THIS MAKES SURE THE UPDATE DOESN'T GET CALLED AGAIN // NEXT FRAME WITHOUT THE USER EXPLICITY REQUESTING IT // BY PRESSING THE 'T' KEY (for Time sTep) activatedForSingleUpdate = false; // WE'LL NEED THE WORLD TO ACCESS THE SPRITES AND WORLD LAYERS GameStateManager *gsm = game->getGSM(); World *world = gsm->getWorld(); // NOTE THAT WE MAKE SURE THE activeCollisions VECTOR IS // EMPTIED BEFORE THIS METHOD EXITS, SO WE CAN ASSUME // IT'S EMPTY NOW. activeCollisions CONTAINS ALL THE COLLISIONS // EMPTIED BEFORE THIS METHOD EXITS, SO WE CAN ASSUME // IT'S EMPTY NOW. activeCollisions CONTAINS ALL THE COLLISIONS // DETECTED SO FAR THIS FRAME. THESE ARE THE THINGS WE MUST // RESOLVE. // START THE CLOCK AT 0, THAT MEANS 0% OF THE WAY THROUGH THE FRAME. // NOTE THAT TIME 0 IS THE MOST DANGEROUS TIME FOR DETECTING COLLISIONS // BECAUSE THEY CAN BE EASILY OVERLOOKED. THE SAME FOR SIMULTANEOUS // COLLISIONS. TO MINIMIZE RIGID BODY PENETRATION, SUCH CIRCUMSTANCES // ARE TYPICALLY HANDLED AS SPECIAL CASES currentCollisionTime = 0.0f; // FIRST WE NEED TO DO COLLISION TESTING PREP WORK FOR SPRITES // APPLY ACCELERATION AND GRAVITY TO VELOCITY // INIT TILE COLLISION INFO // SET ON TILE LAST FRAME USING ON TILE THIS FRAME // SET ON TILE THIS FRAME TO FALSE // GET COLLISIONS WITH ALL TILES TO HAPPEN DURING THIS FRAME // PUT THESE COLLISIONS INTO A SORTABLE DATA STRUCTURE // INIT SPRITE'S SWEPT SHAPE INFO // FOR ALL SPRITES, INCLUDING THE BOTS AND PLAYER vector<CollidableObject*>::iterator spritesIt = sortedSweptShapes[LEFT_EDGE]->begin(); while (spritesIt != sortedSweptShapes[LEFT_EDGE]->end()) { CollidableObject *sprite = (*spritesIt); prepSpriteForCollisionTesting(world, sprite); getAllTileCollisionsForAGivenSprite(world, sprite, 1.0f); spritesIt++; } // PREPARE FOR SPRITE-SPRITE COLLISION TESTING // SWEEP AND PRUNE DATA STRUCTURES PREP WORK // SORT S_AND_P VECTOR SORTED BY START X OF SWEPT SHAPE // SORT S_AND_P VECTOR SORTED BY END X OF SWEPT SHAPE // WE DON'T NEED THE Y-AXIS SORTED, BUT WOULD IF THIS // WERE A 3D SYSTEM TO SAVE ON COMPARISONS. // WE'RE USING C++'s STL sort METHOD AND ARE PROVIDING // A CUSTOM MEANS FOR COMPARISON sort(sortedSweptShapes[LEFT_EDGE]->begin(), sortedSweptShapes[LEFT_EDGE]->end(), SweptShapesComparitorByLeft()); sort(sortedSweptShapes[RIGHT_EDGE]->begin(), sortedSweptShapes[RIGHT_EDGE]->end(), SweptShapesComparitorByRight()); // RECORD SORTED POSITIONS WITH EACH SPRITE. THEY NEED TO KNOW WHERE // THEY ARE IN THOSE DATA STRUCTURES SUCH THAT WE CAN JUMP INTO // THOSE DATA STRUCTURES TO TEST COLLISIONS WITH NEIGHBORS updateSweptShapeIndices(); // YOU'LL NEED TO TEST FOR SPRITE-TO-SPRITE COLLISIONS HERE // *** LOOP STARTS HERE. WE'LL DO THIS UNTIL THERE ARE NO // MORE COLLISIONS TO RESOLVE FOR THIS FRAME while (activeCollisions.size() > 0) { // SORT COLLISION OBJECTS BY TIME OF COLLISION // NOTE THAT I'M JUST EMPLOYING THE STL'S List // CLASS' SORT METHOD BY PROVIDING MY OWN // MEANS FOR COMPARING Collision OBJECTS activeCollisions.sort(CollisionComparitor()); // GET FIRST COLLISION - NOTE THAT WE HAVE THE COLLISIONS SORTED // IN DESCENDING ORDER, SO TO TAKE THE EARLIEST ONE, WE REMOVE IT // FOM THE BACK OF THE SORTED LIST Collision *earliestCollision = activeCollisions.back(); activeCollisions.pop_back(); float collisionTime = earliestCollision->getTimeOfCollision(); // MOVE ALL SPRITES UP TO TIME OF FIRST COLLISION USING // APPROPRIATELY SCALED VELOCITIES moveAllSpritesUpToBufferedTimeOfCollision(earliestCollision); // AND ADVANCE COLLISION TIME currentCollisionTime = collisionTime; // AND UPDATE THE VELOCITIES OF THE SPRITE(S) INVOLVED IN THE COLLISION performCollisionResponse(earliestCollision); // EXECUTE COLLISION EVENT CODE // TEST TO SEE TYPES OF OBJECTS AND APPROPRIATE RESPONSE // ACCORDING TO CUSTOMIZED COLLISION EVENT HANDLER collisionListener->respondToCollision(game, earliestCollision); // FOR THE TWO OBJECTS INVOLVED IN THE COLLISION // REMOVE ALL OTHER COLLISIONS INVOLVING THEM // SINCE THEY ARE NOW OBSOLETE. THE REASON BEING // THE OBJECT COLLISION NOW LIKELY HAS A // DIFFERENT VECTOR // UPDATE THEIR SWEPT SHAPES // TEST THEM AGAINST TILES AGAIN CollidableObject *co1 = earliestCollision->getCO1(); CollidableObject *co2 = earliestCollision->getCO2(); removeActiveCOCollisions(co1); co1->updateSweptShape(1.0f - currentCollisionTime); getAllTileCollisionsForAGivenSprite(world, co1, 1.0f - currentCollisionTime); // ONLY DO IT FOR THE SECOND ONE IF IT'S NOT A TILE if (!earliestCollision->isCollisionWithTile()) { removeActiveCOCollisions(co2); co2->updateSweptShape(1.0f - currentCollisionTime); getAllTileCollisionsForAGivenSprite(world, co2, 1.0f - currentCollisionTime); } else { spriteToTileCollisionsThisFrame[co1].insert(earliestCollision->getTile()); recycledCollidableObjectsList.push_back(co2); } // NOW WE NEED TO SEE IF THE SPRITES INVOLVED IN THE JUST // RESOLVED COLLISION ARE GOING TO BE INVOLVED IN ANY MORE // WITH OTHER SPRITES BUT WE DON'T WANT TO CHECK ALL OF THEM, // WE ONLY WANT TO CHECK NEIGHBORS, BUT FIRST WE HAVE TO // MAKE SURE THE SPRITE(S) THAT WE JUST RESOLVED ARE IN THEIR // PROPER SWEPT SHAPE LOCATIONS WITHOUT HAVING TO RESORT EVERTYHING // IF IT WAS ONLY ONE SPRITE WITH A TILE THIS IS EASY TO DO if (earliestCollision->isCollisionWithTile()) { reorderCollidableObject(co1); } // YOU'LL HAVE TO WORRY ABOUT REORDERING STUFF FOR COLLISIONS // BETWEEN TWO SPRITES // NOW TEST NEIGHBORS OF SPRITES INVOLVED IN RESOLVED COLLISION // AGAINST NEIGHBORS IN SWEPT SHAPE DATA STRUCTURES. YOU'LL HAVE // TO FIGURE OUT HOW TO DO THIS AND HOW TO RESOLVE SUCH COLLISIONS // RECYCLE THE COLLISION SINCE WE'RE NOW DONE WITH IT recycledCollisions.push_back(earliestCollision); } // APPLY THE REMAINING TIME TO MOVE THE SPRITES. NOTE THAT // THIS IS ACTUALLY A VERY RISKY, TRICKY STEP BECAUSE IT COULD // MOVE OBJECTS ALMOST TO THE POINT OF COLLISION, WHICH MAY THEN // BE DETECTED ALMOST AT TIME 0 NEXT FRAME. THERE ARE OTHER TRICKY // ISSUES RELATED TO OUR BUFFER AS WELL, SO WE CHEAT A LITTLE HERE // AND SCALE THE TIME REMAINING DOWN A LITTE if (currentCollisionTime < 1.0f) moveAllSpritesToEndOfFrame(); // INIT TILE COLLISION INFO // SET ON TILE LAST FRAME USING ON TILE THIS FRAME // SET ON TILE THIS FRAME TO FALSE spritesIt = sortedSweptShapes[LEFT_EDGE]->begin(); while (spritesIt != sortedSweptShapes[LEFT_EDGE]->end()) { CollidableObject *sprite = (*spritesIt); sprite->advanceOnTileStatus(); spritesIt++; } // while(!colliding){ for (b2Contact* contact = game->getbworld()->GetContactList(); contact; contact = contact->GetNext()) { b2Body* a = contact->GetFixtureA()->GetBody(); b2Body* b = contact->GetFixtureB()->GetBody(); AnimatedSprite* c = (AnimatedSprite*) a->GetUserData(); AnimatedSprite* d = (AnimatedSprite*) b->GetUserData(); unsigned int x = c->getSpriteType()->getSpriteTypeID(); unsigned int y = d->getSpriteType()->getSpriteTypeID(); switch(x){ case 0: // player break; case 1: // break; case 2: GarbageMon *e; e= (GarbageMon*)c; //co.remove(e); //game->getbworld()->DestroyBody(e->getBody()); //e->collisionResponse(game); break; case 4: //Trash *f = (Trash*)c; //f->collisionResponse(game); break; } switch(y){ // if (x == 0) { case 0: // player break; case 1: // break; case 2: // colliding = true; GarbageMon *g; g= (GarbageMon*)d; co.push_back(g); co.remove(g); //g->setCurrentState(L"DYING"); g->getPhysicalProperties()->setPosition(9999.9f, 9999.9f); game->playExplosion(); //wstring s = c->getCurrentState(); g->getBody()->ApplyLinearImpulse(b2Vec2(99999.9f, 0.0f), g->getBody()->GetPosition(), true); //game->getbworld()->DestroyBody(g->getBody()); //g->getBody()->DestroyFixture(g->getBody()->GetFixtureList()); //g->getBody()->GetWorld()->DestroyBody(g->getBody()); g->collisionResponse(game); //colliding = false; break; case 5: Trash *h = (Trash*)d; co.remove(h); //h->collisionResponse(game); break; } } //} //} //update sprites according to box2d thingies list<CollidableObject*>::iterator i = co.begin(); while (i != co.end()) { CollidableObject* c = *i; PhysicalProperties* p = c->getPhysicalProperties(); p->setX(c->getBody()->GetPosition().x * pikachu); p->setY(c->getBody()->GetPosition().y * pikachu); i++; } float32 time = 1.0f/1.25f; int32 vel = 8; int32 pos = 3; game->getbworld()->Step (time, vel, pos); for (b2Contact* contact = game->getbworld()->GetContactList(); contact; contact = contact->GetNext()) { b2Fixture* a = contact->GetFixtureA(); b2Fixture* b = contact->GetFixtureB(); AnimatedSprite* a2 = (AnimatedSprite*) a->GetBody()->GetUserData(); AnimatedSprite* b2 = (AnimatedSprite*) b->GetBody()->GetUserData(); if(a2->getSpriteType()->getSpriteTypeID() == 0 && b2->getSpriteType()->getSpriteTypeID() == 2){ b->GetBody()->ApplyLinearImpulse(a->GetBody()->GetWorldVector(b2Vec2(0,-2)), b->GetBody()->GetPosition(), true); b->GetBody()->SetLinearVelocity(b2Vec2 (0,0)); SpriteManager *sm = game->getGSM()->getSpriteManager(); int health = (int) _wtoi(sm->getHealthBar()->getCurrentState().c_str()); if (health <= 10){ // WHEN PLAYER RUNS OUT OF HEALTH, SKIP TO NEXT DAY // PENALTY LIES IN THE PLAYER NOT ACHIEVING THE DAY'S GOALS // AND HAVE TO SUFFER INCREASE IN POLLUTION BAR sm->getHealthBar()->setCurrentState(to_wstring(100)); } else{ //OutputDebugStringW(L"HI"); sm->getHealthBar()->setCurrentState(to_wstring(health - 10)); } } //contact->GetFixtureB()->GetBody()->DestroyFixture(a); } // WE'RE NOT GOING TO ALLOW MULTIPLE COLLISIONS TO HAPPEN IN A FRAME // BETWEEN THE SAME TWO OBJECTS spriteToTileCollisionsThisFrame.clear(); }
void Physics::update(Game *game) { // REMEMBER, AT THIS POINT, ALL PLAYER INPUT AND AI // HAVE ALREADY BEEN PROCESSED AND BOT AND PLAYER // STATES, VELOCITIES, AND ACCELERATIONS HAVE ALREADY // BEEN UPDATED. NOW WE HAVE TO PROCESS THE PHYSICS // OF ALL THESE OBJECTS INTERACTING WITH EACH OTHER // AND THE STATIC GAME WORLD. THIS MEANS WE NEED TO // DETECT AND RESOLVE COLLISIONS IN THE ORDER THAT // THEY WILL HAPPEN, AND WITH EACH COLLISION, EXECUTE // ANY GAMEPLAY RESPONSE CODE, UPDATE VELOCITIES, AND // IN THE END, UPDATE POSITIONS // FIRST, YOU SHOULD START BY ADDING ACCELERATION TO ALL // VELOCITIES, WHICH INCLUDES GRAVITY, NOTE THE EXAMPLE // BELOW DOES NOT DO THAT // FOR NOW, WE'LL JUST ADD THE VELOCITIES TO THE // POSITIONS, WHICH MEANS WE'RE NOT APPLYING GRAVITY OR // ACCELERATION AND WE ARE NOT DOING ANY COLLISION // DETECTION OR RESPONSE float timer = 0; GameStateManager *gsm = game->getGSM(); SpriteManager *sm = gsm->getSpriteManager(); World *w = gsm->getWorld(); GameRules* gR = game->getGameRules(); vector<WorldLayer*> *layers = w->getLayers(); AnimatedSprite *player; PhysicalProperties *pp; TiledLayer *tL; list<Collision*> collisions; //finding TileLayer for(unsigned int i = 0; i < layers->size(); i++) { WorldLayer *currentLayer = (*layers)[i]; if(currentLayer->hasCollidableTiles() == true) { tL = dynamic_cast<TiledLayer*>(currentLayer); if(tL != 0) { i = layers->size(); }//end if }//end if } player = sm->getPlayer(); pp = player->getPhysicalProperties(); //UPDATING ALL VELOCITIES AND DOING TILE COLLISION pp->incVelocity(this,pp->getAccelerationX(), pp->getAccelerationY() + gravity); collideTestWithTiles(player, tL, &collisions); list<Bot*>::iterator botIterator = sm->getBotsIterator(); while (botIterator != sm->getEndOfBotsIterator()) { Bot *bot = (*botIterator); pp = bot->getPhysicalProperties(); pp->incVelocity(this, pp->getAccelerationX(), pp->getAccelerationY()); if(pp->isGravAffected() == true) pp->incVelocity(this, 0, gravity); collideTestWithTiles(bot, tL, &collisions); botIterator++; } //HERE, COLLIDE SPRITES WITH OTHER SPRITES collideTestWithSprites(game, player, &collisions); botIterator = sm->getBotsIterator(); while (botIterator != sm->getEndOfBotsIterator()) { Bot *bot = (*botIterator); if(bot->isCurrentlyCollidable() == true); collideTestWithSprites(game, bot, &collisions); botIterator++; } //SORT COLLISIONS collisions.sort(compare_collisionTime); //RESOLVING ALL THE COLLISIONS while(collisions.empty() == false) { Collision* currentCollision = collisions.front(); collisions.pop_front(); float colTime = currentCollision->getTOC(); CollidableObject* co1 = currentCollision->getCO1(); CollidableObject* co2 = currentCollision->getCO2(); if(colTime >= 0 && colTime <= 1) { pp = co1->getPhysicalProperties(); //pp->setVelocity(pp->getVelocityX()*9.99f,pp->getVelocityY()*9.99f); pp = co2->getPhysicalProperties(); //pp->setVelocity(pp->getVelocityX()*9.99f,pp->getVelocityY()*9.99f); pp = player->getPhysicalProperties(); pp->setPosition(pp->getX() + (pp->getVelocityX()*(colTime-timer)),pp->getY() + (pp->getVelocityY()*(colTime-timer))); botIterator = sm->getBotsIterator(); while (botIterator != sm->getEndOfBotsIterator()) { Bot *bot = (*botIterator); pp = bot->getPhysicalProperties(); pp->setPosition(pp->getX() + (pp->getVelocityX()*(colTime-timer)), pp->getY() + (pp->getVelocityY()*(colTime-timer))); botIterator++; } gsm->updateViewport(game, colTime-timer); resolveCollision(game, currentCollision); gR->gameSpecificResolve(game, currentCollision); boolean deleteLast = false; list<Collision*>::iterator cIterator = collisions.begin(); list<Collision*>::iterator lastIterator; while(cIterator != collisions.end()) { if(deleteLast == true) { collisions.erase(lastIterator); } deleteLast = false; Collision* check = (*cIterator); if(check->contains(co1) || check->contains(co2)) { CollidableObject* checkStatic = check->getCO2(); if(checkStatic->isStaticObject()) { coStackCounter ++; coStack[coStackCounter] = checkStatic; } collisionStackCounter ++; collisionStack[collisionStackCounter] = check; lastIterator = cIterator; deleteLast = true; } else { //check->calculateTimes(); } cIterator++; } if(deleteLast == true) { collisions.erase(lastIterator); } collideTestWithTiles(co1, tL, &collisions); collideTestWithSprites(game, co1, &collisions); if(co2->isStaticObject() == false) { collideTestWithTiles(co2, tL, &collisions); collideTestWithSprites(game, co2, &collisions); } collisions.sort(compare_collisionTime); timer += (colTime-timer); }//end if if(co2->isStaticObject() == true) { coStackCounter ++; coStack[coStackCounter] = co2; } collisionStackCounter ++; collisionStack[collisionStackCounter] = currentCollision; } if(timer < 1) { gsm->updateViewport(game, 1-timer); pp = player->getPhysicalProperties(); pp->setPosition(pp->getX() + (pp->getVelocityX()*(1-timer)),pp->getY() + (pp->getVelocityY()*(1-timer))); //pp->setVelocity(0.0f, pp->getVelocityY()); botIterator = sm->getBotsIterator(); while (botIterator != sm->getEndOfBotsIterator()) { Bot *bot = (*botIterator); pp = bot->getPhysicalProperties(); pp->setPosition(pp->getX() + (pp->getVelocityX()*(1-timer)), pp->getY() + (pp->getVelocityY()*(1-timer))); botIterator++; } gsm->updateViewport(game, 1-timer); } pp = player->getPhysicalProperties(); if(pp->getX() < 0) { pp->setX(0); } if(pp->getY() < 0) { pp->setY(0); } //pp->setVelocity(0.0f, pp->getVelocityY()); /*pp->setPosition(pp->getX() + pp->getVelocityX(), pp->getY() + pp->getVelocityY()); // FOR NOW THE PLAYER IS DIRECTLY CONTROLLED BY THE KEYBOARD, // SO WE'LL NEED TO TURN OFF ANY VELOCITY APPLIED BY INPUT // SO THE NEXT FRAME IT DOESN'T GET ADDED pp->setVelocity(0.0f, pp->getVelocityY()); // AND NOW MOVE ALL THE BOTS list<Bot*>::iterator botIterator = sm->getBotsIterator(); while (botIterator != sm->getEndOfBotsIterator()) { Bot *bot = (*botIterator); pp = bot->getPhysicalProperties(); pp->setPosition(pp->getX() + pp->getVelocityX(), pp->getY() + pp->getVelocityY()); botIterator++; }*/ }
void Physics::collideTestWithTiles(CollidableObject *c,TiledLayer *tL, list<Collision*> *collisions) { BoundingVolume *bv = c->getBoundingVolume(); float toRight= bv->getWidth()/2; float toBottom = bv->getHeight()/2; PhysicalProperties *pp = c->getPhysicalProperties(); float x = pp->getX()+bv->getX(); float y = pp->getY()+bv->getY(); float xVel = pp->getVelocityX(); float yVel = pp->getVelocityY(); float minX = x - toRight; float maxX = x + toRight; float minY = y - toBottom; float maxY = y + toBottom; if(xVel > 0) maxX += xVel; else minX += xVel; if(yVel > 0) maxY += yVel; else minY += yVel; int tW = tL->getTileWidth(); int tH = tL->getTileHeight(); int firstCol = minX/tW; int lastCol = maxX/tW; int firstRow = minY/tH; int lastRow = maxY/tH; if(firstCol < 0) firstCol = 0; if(firstRow < 0) firstRow = 0; if(lastCol >= tL->getColumns()) lastCol = tL->getColumns() - 1; if(lastRow >= tL->getRows()) lastRow = tL->getRows() - 1; for(int i = firstRow; i <= lastRow; i++) { for(int j = firstCol; j <= lastCol; j++) { Tile* current = tL->getTile(i,j); if(current->collidable == true) { if( !( (i+1)*tH < minY || i*tH > maxY || (j+1)*tW < minX || j*tW > maxX) ) { CollidableObject* tileCO = coStack[coStackCounter]; coStackCounter --; BoundingVolume *bv = tileCO->getBoundingVolume(); bv->setWidth(tW); bv->setHeight(tH); bv->setX(tW/2); bv->setY(tW/2); pp = tileCO->getPhysicalProperties(); pp->setPosition(j*tW,i*tH); /* Collision* currentCollision = collisionStack.top(); collisionStack.pop();*/ Collision* currentCollision = collisionStack[collisionStackCounter]; collisionStackCounter --; currentCollision->setCO1(c); currentCollision->setCO2(tileCO); currentCollision->calculateTimes(); collisions->push_back(currentCollision); } } } } }
void createLevel(){ //DEPENDS ON THE LEVEL I GUESS bgColor = WHITE; //FRAME float floorW = 200; float floorH = 20; dimensionsHorizontal = Point2<float>(floorW, floorH); dimensionsVertical = Point2<float>(floorH, floorW); groundTex = loadPNG("death.png"); //groundTex = characterTex; CollidableObject floor = CollidableObject(Point2f(400,20), Point2<float>(100, -100), CollidableObject::PLATFORM); floor.setColour(GREY); obstacles.push_back(floor); CollidableObject floorDEATH = CollidableObject(Point2f(400, 20), Point2<float>(100, -120), CollidableObject::DEADLYPLATFORM); floorDEATH.setColour(BLACK); floorDEATH.setTexture(groundTex); obstacles.push_back(floorDEATH); CollidableObject ceiling = CollidableObject(dimensionsHorizontal, Point2<float>(0, 100), CollidableObject::PLATFORM); ceiling.setColour(GREY); //obstacles.push_back(ceiling); CollidableObject wallLeft = CollidableObject(dimensionsVertical, Point2<float>(-100, 0), CollidableObject::PLATFORM); wallLeft.setColour(GREY); obstacles.push_back(wallLeft); CollidableObject wallRight = CollidableObject(dimensionsVertical, Point2<float>(100, 0), CollidableObject::PLATFORM); wallRight.setColour(GREY); //obstacles.push_back(wallRight); //PLATFORMS CollidableObject platform1 = CollidableObject(Point2f(60, 20), Point2<float>(0, -40), CollidableObject::PLATFORM); platform1.setColour(BLUE); obstacles.push_back(platform1); //PLATFORMS CollidableObject platform2 = CollidableObject(Point2f(60, 20), Point2<float>(100, -20), CollidableObject::PLATFORM); platform2.setColour(BLUE); obstacles.push_back(platform2); CollidableObject platform3 = CollidableObject(Point2f(60, 20), Point2<float>(220,10), CollidableObject::PLATFORM); platform3.setColour(BLUE); obstacles.push_back(platform3); CollidableObject platform4 = CollidableObject(Point2f(60, 20), Point2<float>(120, 70), CollidableObject::PLATFORM); platform4.setColour(GREY); obstacles.push_back(platform4); }