/* Done each frame before collision testing, it updates the "on tile" states and then applies acceleration and gravity to the sprite's velocity. Then it initializes the swept shape for the sprite. */ void Physics::prepSpriteForCollisionTesting(World *world, CollidableObject *sprite) { // THIS GUY HAS ALL THE PHYSICS STUFF FOR THE SPRITE PhysicalProperties *pp = sprite->getPhysicalProperties(); // APPLY ACCELERATION pp->applyAcceleration(); // APPLY GRAVITY pp->incVelocity(0.0f, gravity); // NOW, IF THE SPRITE WAS ON A TILE LAST FRAME LOOK AHEAD // TO SEE IF IT IS ON A TILE NOW. IF IT IS, UNDO GRAVITY. // THIS HELPS US AVOID SOME PROBLEMS if (sprite->wasOnTileLastFrame()) { // FIRST MAKE SURE IT'S SWEPT SHAPE ACCOUNTS FOR GRAVITY sprite->updateSweptShape(1.0f); // WE'LL LOOK THROUGH THE COLLIDABLE LAYERS vector<WorldLayer*> *layers = world->getLayers(); for (int i = 0; i < world->getNumLayers(); i++) { WorldLayer *layer = layers->at(i); if (layer->hasCollidableTiles()) { bool test = layer->willSpriteCollideOnTile(this, sprite); if (test) { sprite->setOnTileThisFrame(true); pp->setVelocity(pp->getVelocityX(), 0.0f); sprite->updateSweptShape(1.0f); return; } else cout << "What Happened?"; } } } // INIT THE SWEPT SHAPE USING THE NEWLY APPLIED // VELOCITY. NOTE THAT 100% OF THE FRAME TIME // IS LEFT, DENOTED BY 1.0f sprite->updateSweptShape(1.0f); }
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++; }*/ }