bool Physics::willObjectsCollide(CollidableObject* coA, CollidableObject* coB) { PhysicalProperties* pp = coA->getPhysicalProperties(); BoundingVolume* bv = coA->getBoundingVolume(); float widthA = bv->getWidth(); float heightA = bv->getHeight(); float xA = pp->getX() + bv->getX(); float yA = pp->getY() + bv->getY(); float velXA = pp->getVelocityX(); float velYA = pp->getVelocityY(); float minXA = xA-(widthA/2); float maxXA = xA+(widthA/2); float minYA = yA-(heightA/2); float maxYA = yA+(heightA/2); if(velXA >= 0) maxXA += velXA; if(velXA < 0) minXA += velXA; if(velYA >= 0) maxYA += velYA; if(velYA < 0) minYA += velYA; pp = coB->getPhysicalProperties(); bv = coB->getBoundingVolume(); float widthB = bv->getWidth(); float heightB = bv->getHeight(); float xB = pp->getX() + bv->getX(); float yB = pp->getY() + bv->getY(); float velXB = pp->getVelocityX(); float velYB = pp->getVelocityY(); float minXB = xB-(widthB/2); float maxXB = xB+(widthB/2); float minYB = yB-(heightB/2); float maxYB = yB+(heightB/2); if(velXB >= 0) maxXB += velXB; if(velXB < 0) minXB += velXB; if(velYB >= 0) maxYB += velYB; if(velYB < 0) minYB += velYB; if( !(maxXB < minXA || minXB > maxXA || maxYB < minYA || minYB > maxYA)) return true; return false; }
/* update - This method should be called once per frame. It updates both the sprites and the game world. Note that even though the game world is for static data, should the user wish to put anything dynamic there (like a non-collidable moving layer), the updateWorld method is called. */ void GameStateManager::update(Game *game) { game->getGameRules()->spawnEnemies(game); spriteManager->update(game); world.update(game); physics.update(game); AnimatedSprite *p = spriteManager->getPlayer(); PhysicalProperties *pp = p->getPhysicalProperties(); float pVelX = pp->getVelocityX(); float pVelY = pp->getVelocityY(); //VIEWPORT SCOPING /*Viewport *vp = game->getGUI()->getViewport(); if(pVelX < 0 && (pp->round(pp->getX() - vp->getViewportX())) < vp->getViewportWidth()/3) { vp->setScrollSpeedX(pVelX); if(vp->getViewportX() == 0) vp->setScrollSpeedX(0); } else if(pVelX > 0 && (pp->round(pp->getX() - vp->getViewportX())) > (vp->getViewportWidth()/3*2)) { vp->setScrollSpeedX(pVelX); if(vp->getViewportX()+vp->getViewportWidth() == world.getWorldWidth()) vp->setScrollSpeedX(0); } else { vp->setScrollSpeedX(0); } if(pVelY < 0 && (pp->round(pp->getY() - vp->getViewportY())) < vp->getViewportHeight()/3) { vp->setScrollSpeedY(pVelY); if(vp->getViewportY() == 0) vp->setScrollSpeedY(0); } else if(pVelY > 0 && (pp->round(pp->getY() - vp->getViewportY())) > (vp->getViewportHeight()/3*2)) { vp->setScrollSpeedY(pVelY); if(vp->getViewportY()+vp->getViewportHeight() == world.getWorldHeight()) vp->setScrollSpeedY(0); } else { vp->setScrollSpeedY(0); } vp->moveViewport( vp->getScrollSpeedX(), vp->getScrollSpeedY(), world.getWorldWidth(), world.getWorldHeight());*/ }
/* This method helps us employ walking and jumping on/from tiles. It is a look ahead function which basically tells us if the sprite (co) will collide on top of the tile's AABB. */ bool Physics::willSpriteCollideOnTile(CollidableObject *co, AABB *tileAABB) { // yBottom < 0 is collision float yBottomDiff = tileAABB->getTop() - co->getBoundingVolume()->getBottom() + co->getPhysicalProperties()->getVelocityY(); // xRight < 0 is collision float xRightDiff = tileAABB->getLeft() - co->getBoundingVolume()->getRight() + co->getPhysicalProperties()->getVelocityX(); // yTop > 0 is collision float yTopDiff = tileAABB->getBottom() - co->getBoundingVolume()->getTop() + co->getPhysicalProperties()->getVelocityY(); // xLeft > 0 is collision float xLeftDiff = tileAABB->getRight() - co->getBoundingVolume()->getLeft() + co->getPhysicalProperties()->getVelocityX(); PhysicalProperties *pp = co->getPhysicalProperties(); if (pp->getVelocityX() > 0.0f) return (xRightDiff < -20.0f); if (pp->getVelocityX() < 0.0f) return (xLeftDiff > 20.0f); if (pp->getVelocityY() > 0.0f) return (yBottomDiff < -20.0f); if (pp->getVelocityY() < 0.0f) return (yTopDiff > 20.0f); return false; }
/* 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); }
/* think - called once per frame, this is where the bot performs its decision-making. Note that we might not actually do any thinking each frame, depending on the value of cyclesRemainingBeforeThinking. */ void BackAndForthBot::think(Game *game) { // EACH FRAME WE'LL TEST THIS BOT TO SEE IF WE NEED // TO PICK A DIFFERENT DIRECTION TO FLOAT IN PhysicalProperties* pp = &(this->pp); if(!dead) { if(pp->getVelocityX() == 0) { pp->setVelocity(vel, pp->getVelocityY()); } if (cyclesRemainingBeforeChange == 0) { vel *= -1; pp->setVelocity(vel, pp->getVelocityY()); if(pp->isOrientedRight()) { this->setCurrentState(L"WALKL_STATE"); pp->setOrientedLeft(); } else { this->setCurrentState(L"WALK_STATE"); pp->setOrientedRight(); } cyclesRemainingBeforeChange = pathSize; } else cyclesRemainingBeforeChange--; } else { wstring curState = this->getCurrentState(); pp->setVelocity(0,pp->getVelocityY()); int lastFrame = this->getSpriteType()->getSequenceSize(curState)-2; if(this->getFrameIndex() == lastFrame) { game->getGSM()->getSpriteManager()->removeBot(this); } } }
/* handleKeyEvent - this method handles all keyboard interactions. Note that every frame this method gets called and it can respond to key interactions in any custom way. Ask the GameInput class for key states since the last frame, which can allow us to respond to key presses, including when keys are held down for multiple frames. */ void BugsKeyEventHandler::handleKeyEvents(Game *game) { // WE CAN QUERY INPUT TO SEE WHAT WAS PRESSED GameInput *input = game->getInput(); // LET'S GET THE PLAYER'S PHYSICAL PROPERTIES, IN CASE WE WANT TO CHANGE THEM GameStateManager *gsm = game->getGSM(); AnimatedSprite *player = gsm->getSpriteManager()->getPlayer(); PhysicalProperties *pp = player->getPhysicalProperties(); Viewport *viewport = game->getGUI()->getViewport(); // IF THE GAME IS IN PROGRESS if (gsm->isGameInProgress()) { if (input->isKeyDownForFirstTime(D_KEY)) { viewport->toggleDebugView(); game->getGraphics()->toggleDebugTextShouldBeRendered(); } if (input->isKeyDownForFirstTime(L_KEY)) { game->getGraphics()->togglePathfindingGridShouldBeRendered(); } if (input->isKeyDownForFirstTime(F_KEY)) { game->getGraphics()->togglePathfindingPathShouldBeRendered(); } if (input->isKeyDownForFirstTime(R_KEY)) { if (wcscmp(player->getCurrentState().c_str(), L"RUNNING") == 0) player->setCurrentState(L"WALKING"); else if ((wcscmp(player->getCurrentState().c_str(), L"IDLE") != 0) && (wcscmp(player->getCurrentState().c_str(), L"DANCING") != 0)) player->setCurrentState(L"RUNNING"); } if (input->isKeyDownForFirstTime(Y_KEY)){ player->setCurrentState(DYING); } if (input->isKeyDownForFirstTime(I_KEY)){ player->setCurrentState(IDLE); } bool viewportMoved = false; float viewportVx = 0.0f; float viewportVy = 0.0f; float vX = pp->getVelocityX(); float vY = pp->getVelocityY(); if (input->isKeyDown(UP_KEY)) { if (pp->getY() < (viewport->getViewportY() + 0.5f * viewport->getViewportHeight())) viewportVy -= MAX_PLAYER_VELOCITY; vY = -1 * MAX_PLAYER_VELOCITY; vX = 0; viewportMoved = true; } else if (input->isKeyDown(DOWN_KEY)) { if (pp->getY() > (viewport->getViewportY() + 0.5f * viewport->getViewportHeight())) viewportVy += MAX_PLAYER_VELOCITY; vY = MAX_PLAYER_VELOCITY; vX = 0; viewportMoved = true; } else if (input->isKeyDown(LEFT_KEY)) { if (pp->getX() < (viewport->getViewportX() + 0.5f * viewport->getViewportWidth())) viewportVx -= MAX_PLAYER_VELOCITY; vX = -1 * MAX_PLAYER_VELOCITY; vY = 0; viewportMoved = true; } else if (input->isKeyDown(RIGHT_KEY)) { if (pp->getX() > (viewport->getViewportX() + 0.5f * viewport->getViewportWidth())) viewportVx += MAX_PLAYER_VELOCITY; vX = MAX_PLAYER_VELOCITY; vY = 0; viewportMoved = true; } else { vX = 0.0f; vY = 0.0f; } if (viewportMoved) viewport->moveViewport((int)floor(viewportVx+0.5f), (int)floor(viewportVy+0.5f), game->getGSM()->getWorld()->getWorldWidth(), game->getGSM()->getWorld()->getWorldHeight()); pp->setVelocity(vX, vY); } // 0X43 is HEX FOR THE 'C' VIRTUAL KEY // THIS CHANGES THE CURSOR IMAGE if ((input->isKeyDownForFirstTime(C_KEY)) && input->isKeyDown(VK_SHIFT)) { Cursor *cursor = game->getGUI()->getCursor(); unsigned int id = cursor->getActiveCursorID(); id++; if (id == cursor->getNumCursorIDs()) id = 0; cursor->setActiveCursorID(id); } // LET'S MESS WITH THE TARGET FRAME RATE IF THE USER PRESSES THE HOME OR END KEYS WindowsTimer *timer = (WindowsTimer*)game->getTimer(); int fps = timer->getTargetFPS(); // THIS SPEEDS UP OUR GAME LOOP AND THUS THE GAME, NOTE THAT WE COULD ALTERNATIVELY SCALE // DOWN THE GAME LOGIC (LIKE ALL VELOCITIES) AS WE SPEED UP THE GAME. THAT COULD PROVIDE // A BETTER PLAYER EXPERIENCE if (input->isKeyDown(VK_HOME) && (fps < MAX_FPS)) timer->setTargetFPS(fps + FPS_INC); // THIS SLOWS DOWN OUR GAME LOOP, BUT WILL NOT GO BELOW 5 FRAMES PER SECOND else if (input->isKeyDown(VK_END) && (fps > MIN_FPS)) timer->setTargetFPS(fps - FPS_INC); }
/* handleKeyEvent - this method handles all keyboard interactions. Note that every frame this method gets called and it can respond to key interactions in any custom way. Ask the GameInput class for key states since the last frame, which can allow us to respond to key presses, including when keys are held down for multiple frames. */ void SoSKeyEventHandler::handleKeyEvents(Game *game) { // WE CAN QUERY INPUT TO SEE WHAT WAS PRESSED GameInput *input = game->getInput(); // LET'S GET THE PLAYER'S PHYSICAL PROPERTIES, IN CASE WE WANT TO CHANGE THEM GameStateManager *gsm = game->getGSM(); AnimatedSprite *player = gsm->getSpriteManager()->getPlayer(); PhysicalProperties *pp = player->getPhysicalProperties(); if(gsm->isAtSplashScreen()) { if(input->isKeyDown(ENTER_KEY)) { gsm->goToMainMenu(); } } // IF THE GAME IS IN PROGRESS if (gsm->isGameInProgress()) { // CHECK FOR WASD KEYS FOR MOVEMENT int incX = 0; int incY = 0; bool movingLR = false; bool attacking = false; if(!pp->isStunned()) { if(input->isKeyDown(SPACE_KEY)) { attacking = true; if(input->isKeyDownForFirstTime(SPACE_KEY)) { player->setCurrentState(L"ATTACK_STATE"); if(!pp->isOrientedRight()) player->setCurrentState(L"ATTACKL_STATE"); } } // WASD AND DIRECTION KEY PRESSES WILL CONTROL THE PLAYER, // SO WE'LL UPDATE THE PLAYER VELOCITY WHEN THESE KEYS ARE // PRESSED, THAT WAY PHYSICS CAN CORRECT AS NEEDED float vX = pp->getVelocityX(); float vY = pp->getVelocityY(); if (input->isKeyDown(A_KEY) || input->isKeyDown(LEFT_KEY)) { movingLR = true; pp->setOrientedLeft(); vX = -PLAYER_SPEED; if (vY == 0 && player->getCurrentState().compare(L"LEFT_STATE") != 0) player->setCurrentState(L"LEFT_STATE"); else if(vY != 0 && player->getCurrentState().compare(L"JUMPL_STATE") != 0) player->setCurrentState(L"JUMPL_STATE"); } if (input->isKeyDown(D_KEY) || input->isKeyDown(RIGHT_KEY)) { movingLR = true; pp->setOrientedRight(); vX = PLAYER_SPEED; if (vY == 0 && player->getCurrentState().compare(L"RIGHT_STATE") != 0) player->setCurrentState(L"RIGHT_STATE"); else if(vY != 0 && player->getCurrentState().compare(L"JUMP_STATE") != 0) player->setCurrentState(L"JUMP_STATE"); } /*if (input->isKeyDown(S_KEY) || input->isKeyDown(DOWN_KEY)) { vY = PLAYER_SPEED; }*/ if (input->isKeyDown(W_KEY) || input->isKeyDown(UP_KEY)) { if ((input->isKeyDownForFirstTime(W_KEY) || input->isKeyDownForFirstTime(UP_KEY)) && pp->hasDoubleJumped() == false) { if(pp->hasJumped() == true) pp->setDoubleJumped(true); pp->setJumped(true); vY = -PLAYER_SPEED; player->setCurrentState(L"JUMP_STATE"); if(vX < 0) player->setCurrentState(L"JUMPL_STATE"); } } if(!movingLR) { vX = 0; } if(vY == 0 && vX == 0 && !attacking && player->getCurrentState().compare(L"IDLE_STATE") != 0 && player->getCurrentState().compare(L"IDLEL_STATE") != 0 ) { player->setCurrentState(L"IDLE_STATE"); if(!pp->isOrientedRight()) player->setCurrentState(L"IDLEL_STATE"); } // NOW SET THE ACTUAL VELOCITY Physics *physics = gsm->getPhysics(); pp->setVelocitySafely(physics, vX, vY); } // NOTE THAT THE VIEWPORT SHOULD FOLLOW THE PLAYER, AND SO SHOULD BE CORRECTED AFTER PHYSICS // ARE APPLIED. I HAVE PROVIDED A SIMPLE WAY OF DOING SO, WHICH SHOULD BE IMPROVED, DEPENDING // ON THE GAME'S NEED if(input->isKeyDownForFirstTime(TAB_KEY)) { gsm->goToPaused(); } } else if(gsm->isGamePaused() && input->isKeyDownForFirstTime(TAB_KEY)) { gsm->goToGame(); } // 0X43 is HEX FOR THE 'C' VIRTUAL KEY // THIS CHANGES THE CURSOR IMAGE if ((input->isKeyDownForFirstTime(C_KEY)) && input->isKeyDown(VK_SHIFT)) { Cursor *cursor = game->getGUI()->getCursor(); unsigned int id = cursor->getActiveCursorID(); id++; if (id == cursor->getNumCursorIDs()) id = 0; cursor->setActiveCursorID(id); } // LET'S MESS WITH THE TARGET FRAME RATE IF THE USER PRESSES THE HOME OR END KEYS WindowsTimer *timer = (WindowsTimer*)game->getTimer(); int fps = timer->getTargetFPS(); // THIS SPEEDS UP OUR GAME LOOP AND THUS THE GAME, NOTE THAT WE COULD ALTERNATIVELY SCALE // DOWN THE GAME LOGIC (LIKE ALL VELOCITIES) AS WE SPEED UP THE GAME. THAT COULD PROVIDE // A BETTER PLAYER EXPERIENCE if (input->isKeyDown(VK_HOME) && (fps < MAX_FPS)) timer->setTargetFPS(fps + FPS_INC); // THIS SLOWS DOWN OUR GAME LOOP, BUT WILL NOT GO BELOW 5 FRAMES PER SECOND else if (input->isKeyDown(VK_END) && (fps > MIN_FPS)) timer->setTargetFPS(fps - FPS_INC); }
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::resolveCollision(Game* game, Collision* currentCollision) { CollidableObject* co1 = currentCollision->getCO1(); CollidableObject* co2 = currentCollision->getCO2(); PhysicalProperties* pp; BoundingVolume* bv; AnimatedSprite* player = game->getGSM()->getSpriteManager()->getPlayer(); if(co2->isStaticObject() == true) { pp = co2->getPhysicalProperties(); bv = co2->getBoundingVolume(); float tX = pp->getX(); float tY = pp->getY(); float tXR = tX + bv->getWidth(); float tYB = tY + bv->getHeight(); pp = co1->getPhysicalProperties(); bv = co1->getBoundingVolume(); float x = pp->getX() + bv->getX() - (bv->getWidth()/2); float y = pp->getY() + bv->getY() - (bv->getHeight()/2); float xR = x+bv->getWidth(); float yB = y+bv->getHeight(); //pp->setVelocity(0, 0); /*if(x < tX) pp->setX(pp->getX() - 0.1); if(x > tX) pp->setX(pp->getX() + 0.1);*/ if(x >= tXR) { pp->setX(pp->getX() + 0.1); pp->setVelocity(0, pp->getVelocityY()); } if(xR <= tX) { pp->setX(pp->getX() - 0.1); pp->setVelocity(0, pp->getVelocityY()); } if(y >= tYB) { pp->setY(pp->getY() + 0.1); pp->setVelocity(pp->getVelocityX(), 0); } if(yB <= tY) { pp->setY(pp->getY() - 0.1); if(co1 == player) { pp->setJumped(false); pp->setDoubleJumped(false); pp->setStunned(false); } pp->setVelocity(pp->getVelocityX(), 0); } //if(currentCollision->getTOC() == currentCollision->getSYC()) //{ // /*if(pp->getVelocityY() < 0) // { // pp->setY(pp->getY() + 0.1); // } // else // { // pp->setY(pp->getY() - 0.1); // if(co1 == player) // { // pp->setJumped(false);s // pp->setDoubleJumped(false); // if(player->getCurrentState().compare(L"JUMP_STATE") == 0 // || player->getCurrentState().compare(L"JUMPL_STATE") == 0) // { // player->setCurrentState(L"IDLE_STATE"); // } // } // }*/ // if(y < tY) // { // pp->setY(pp->getY() - 0.1); // if(co1 == player) // { // pp->setJumped(false); // pp->setDoubleJumped(false); // /*if(player->getCurrentState().compare(L"JUMP_STATE") == 0 // || player->getCurrentState().compare(L"JUMPL_STATE") == 0) // { // player->setCurrentState(L"IDLE_STATE"); // }*/ // } // } // if(y > tY) // { // pp->setY(pp->getY() + 0.1); // // } // pp->setVelocity(pp->getVelocityX(), 0); // // //} //else if(currentCollision->getTOC() == currentCollision->getSXC()) //{ // /*if(pp->getVelocityX() < 0) // { // pp->setX(pp->getX() + 0.1); // } // else // { // pp->setX(pp->getX() - 0.1); // }*/ // /*if(x < tX) // pp->setX(pp->getX() - 0.1); // if(x > tX) // pp->setX(pp->getX() + 0.1);*/ // pp->setVelocity(0, pp->getVelocityY()); //} //else //{ // /*if(pp->getVelocityY() < 0) // pp->setY(pp->getY() + 0.1); // else // pp->setY(pp->getY() - 0.1); // if(pp->getVelocityX() < 0) // pp->setX(pp->getX() + 0.1); // else // pp->setX(pp->getX() - 0.1);*/ // pp->setVelocity(0,0); //} } else { pp = co1->getPhysicalProperties(); bv = co1->getBoundingVolume(); float x = pp->getX()+ bv->getX() - (bv->getWidth()/2); float y = pp->getY()+ bv->getY() - (bv->getHeight()/2); float xR = x + bv->getWidth(); float yB = y + bv->getHeight(); PhysicalProperties* p2 = co2->getPhysicalProperties(); bv = co2->getBoundingVolume(); float tX = p2->getX() + bv->getX() - (bv->getWidth()/2); float tY = p2->getY() + bv->getY() - (bv->getHeight()/2); float tXR = tX+bv->getWidth(); float tYB = tY+bv->getHeight(); //pp->setVelocity(0, 0); if(x >= tXR) { if(co1->isMobile()) pp->setX(pp->getX() + 0.1); if(co2->isMobile()) p2->setX(p2->getX() - 0.1); } if(xR <= tX) { if(co1->isMobile()) pp->setX(pp->getX() - 0.1); if(co2->isMobile()) p2->setX(p2->getX() + 0.1); } if(y >= tYB) { if(co1->isMobile()) pp->setY(pp->getY() + 0.1); if(co2->isMobile()) p2->setY(p2->getY() - 0.1); } if(yB <= tY) { if(co1->isMobile()) pp->setY(pp->getY() - 0.1); if(co2->isMobile()) p2->setY(p2->getY() + 0.1); } } }
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); } } } } }
/* handleKeyEvent - this method handles all keyboard interactions. Note that every frame this method gets called and it can respond to key interactions in any custom way. Ask the GameInput class for key states since the last frame, which can allow us to respond to key presses, including when keys are held down for multiple frames. */ void BugginOutKeyEventHandler::handleKeyEvents(Game *game) { // WE CAN QUERY INPUT TO SEE WHAT WAS PRESSED GameInput *input = game->getInput(); // LET'S GET THE PLAYER'S PHYSICAL PROPERTIES, IN CASE WE WANT TO CHANGE THEM GameStateManager *gsm = game->getGSM(); AnimatedSprite *player = gsm->getSpriteManager()->getPlayer(); list<AnimatedSprite*>::iterator blocks; PhysicalProperties *pp = player->getPhysicalProperties(); Viewport *viewport = game->getGUI()->getViewport(); // IF THE GAME IS IN PROGRESS if (gsm->isGameInProgress()) { Physics *phy = game->getGSM()->getPhysics(); // WASD KEY PRESSES WILL CONTROL THE PLAYER // SO WE'LL UPDATE THE PLAYER VELOCITY WHEN THESE KEYS ARE // PRESSED, THAT WAY PHYSICS CAN CORRECT AS NEEDED float vX = pp->getVelocityX(); float vY = pp->getVelocityY(); // YOU MIGHT WANT TO UNCOMMENT THIS FOR SOME TESTING, b2Body *body = player->body; if (game->getGSM()->levelSwitchTrigger == true) { game->quitGame(); if (game->getCurrentLevelFileName() == W_LEVEL_1_NAME) game->setCurrentLevelFileName(W_LEVEL_2_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_2_NAME) game->setCurrentLevelFileName(W_LEVEL_3_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_3_NAME) game->setCurrentLevelFileName(W_LEVEL_4_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_4_NAME) game->setCurrentLevelFileName(W_LEVEL_5_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_5_NAME) game->setCurrentLevelFileName(W_LEVEL_6_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_6_NAME) game->setCurrentLevelFileName(W_LEVEL_7_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_7_NAME) game->setCurrentLevelFileName(W_LEVEL_8_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_8_NAME) game->setCurrentLevelFileName(W_LEVEL_9_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_9_NAME) game->setCurrentLevelFileName(W_LEVEL_10_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_10_NAME) game->setCurrentLevelFileName(W_LEVEL_1_NAME); game->startGame(); game->getGSM()->levelSwitchTrigger = false; } if (game->getGSM()->levelResetTrigger == true) { game->quitGame(); if (game->getCurrentLevelFileName() == W_LEVEL_1_NAME) game->setCurrentLevelFileName(W_LEVEL_1_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_2_NAME) game->setCurrentLevelFileName(W_LEVEL_2_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_3_NAME) game->setCurrentLevelFileName(W_LEVEL_3_NAME); else if (game->getCurrentLevelFileName() == W_LEVEL_4_NAME) game->setCurrentLevelFileName(W_LEVEL_4_NAME); game->startGame(); game->getGSM()->levelResetTrigger = false; } if (input->isKeyDown('1')){ game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_1_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_1_NAME); /*game->setCurrentLevelFileName(W_LEVEL_1_NAME); game->startGame();*/ } else if (input->isKeyDown('2')){ game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_2_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_2_NAME); } else if (input->isKeyDown('3')){ game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_3_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_3_NAME); } else if (input->isKeyDown('4')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_4_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown('5')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_5_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown('6')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_6_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown('7')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_7_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown('8')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_8_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown('9')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_9_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown('0')) { game->quitGame(); game->setCurrentLevelFileName(W_LEVEL_10_NAME); game->startGame(); //game->getGSM()->unloadCurrentLevel(); //game->getGSM()->loadLevel(game, W_LEVEL_1_DIR + W_LEVEL_4_NAME); } else if (input->isKeyDown(A_KEY)) { if (player->dead == false) { pp->facing = 1; if ((phy->CurrentGrav == phy->Normal_Grav || phy->CurrentGrav == phy->Reverse_Grav)) { if (player->onGround()) body->ApplyForce(b2Vec2(body->GetMass() * -0.1 / (1 / 60.0), 0), body->GetWorldCenter(), true); else body->ApplyForce(b2Vec2(body->GetMass() * -0.1 / (1 / 60.0), 0), body->GetWorldCenter(), true); } if ((phy->CurrentGrav == phy->Left_Grav || phy->CurrentGrav == phy->Right_Grav)) { if (player->onGround()) body->ApplyForce(b2Vec2(0, body->GetMass() * -0.1 / (1 / 60.0)), body->GetWorldCenter(), true); else body->ApplyForce(b2Vec2(0, body->GetMass() * -0.1 / (1 / 60.0)), body->GetWorldCenter(), true); } if (player->onGround()) { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(LWALK); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(ULWALK); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RLWALK); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LLWALK); } else { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(LFALL); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(ULFALL); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RLFALL); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LLFALL); } } } else if (input->isKeyDown(D_KEY)) { if (player->dead == false) { pp->facing = 0; if ((phy->CurrentGrav == phy->Normal_Grav || phy->CurrentGrav == phy->Reverse_Grav)) { if (player->onGround()) body->ApplyForce(b2Vec2(body->GetMass() * 0.1 / (1 / 60.0), 0), body->GetWorldCenter(), true); else body->ApplyForce(b2Vec2(body->GetMass() * 0.1 / (1 / 60.0), 0), body->GetWorldCenter(), true); } if ((phy->CurrentGrav == phy->Left_Grav || phy->CurrentGrav == phy->Right_Grav)) { if (player->onGround()) body->ApplyForce(b2Vec2(0, body->GetMass() * 0.1 / (1 / 60.0)), body->GetWorldCenter(), true); else body->ApplyForce(b2Vec2(0, body->GetMass() * 0.1 / (1 / 60.0)), body->GetWorldCenter(), true); } if (player->onGround()) { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(RWALK); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(URWALK); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RRWALK); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LRWALK); } else { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(RFALL); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(URFALL); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RRFALL); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LRFALL); } } } else if (input->isKeyDownForFirstTime(G_KEY)) { /*((BugginOutDataLoader*)game->getDataLoader())->remotePlaySound(((BugginOutDataLoader*)game->getDataLoader())->gravSound); b2World *world = game->getGSM()->getPhysics()->getBoxWorld(); if (phy->CurrentGrav == phy->Normal_Grav) { player->body->SetTransform(player->body->GetPosition(), 0.0f); blocks = gsm->getSpriteManager()->getBlocksIterator(); while (blocks != gsm->getSpriteManager()->getEndOfBlocksIterator()) { (*blocks)->body->SetGravityScale(1); blocks++; } world->SetGravity(phy->Reverse_Grav); phy->CurrentGrav = phy->Reverse_Grav; } else if (phy->CurrentGrav == phy->Reverse_Grav) { player->body->SetTransform(player->body->GetPosition(), 270.0f); blocks = gsm->getSpriteManager()->getBlocksIterator(); while (blocks != gsm->getSpriteManager()->getEndOfBlocksIterator()) { (*blocks)->body->SetGravityScale(0); blocks++; } world->SetGravity(phy->Left_Grav); phy->CurrentGrav = phy->Left_Grav; } else if (phy->CurrentGrav == phy->Left_Grav) { player->body->SetTransform(player->body->GetPosition(), 270.0f); blocks = gsm->getSpriteManager()->getBlocksIterator(); while (blocks != gsm->getSpriteManager()->getEndOfBlocksIterator()) { (*blocks)->body->SetGravityScale(0); blocks++; } world->SetGravity(phy->Right_Grav); phy->CurrentGrav = phy->Right_Grav; } else if (phy->CurrentGrav == phy->Right_Grav) { player->body->SetTransform(player->body->GetPosition(), 0.0f); blocks = gsm->getSpriteManager()->getBlocksIterator(); while (blocks != gsm->getSpriteManager()->getEndOfBlocksIterator()) { (*blocks)->body->SetGravityScale(1); blocks++; } world->SetGravity(phy->Normal_Grav); phy->CurrentGrav = phy->Normal_Grav; } player->setGrounded(false);*/ } else if (player->onGround()) { if (player->dead == false) { if (pp->facing == 0) { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(RIDLE); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(URIDLE); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RRIDLE); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LRIDLE); } else { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(LIDLE); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(ULIDLE); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RLIDLE); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LLIDLE); } } else { if (player->getCurrentState() != L"LDEATH") { if (pp->facing == 0){ if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(RFALL); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(URFALL); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RRFALL); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LRFALL); } else{ if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(LFALL); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(ULFALL); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RLFALL); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LLFALL); } } } } if (input->isKeyDownForFirstTime(SPACE_KEY) && player->onGround() && player->dead == false) { ((BugginOutDataLoader*)game->getDataLoader())->remotePlaySound(((BugginOutDataLoader*)game->getDataLoader())->jumpSound); //float mass = body->GetMass(); float impulse = 3.0f; if (phy->CurrentGrav == phy->Normal_Grav) { body->SetLinearVelocity(b2Vec2(body->GetLinearVelocity().x, -impulse)); } if (phy->CurrentGrav == phy->Reverse_Grav) { body->SetLinearVelocity(b2Vec2(body->GetLinearVelocity().x, impulse)); } if (phy->CurrentGrav == phy->Right_Grav) { body->SetLinearVelocity(b2Vec2(-impulse, body->GetLinearVelocity().y)); } if (phy->CurrentGrav == phy->Left_Grav) { body->SetLinearVelocity(b2Vec2(impulse, body->GetLinearVelocity().y)); } if (pp->facing == 0) { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(RJUMP); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(URJUMP); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RRJUMP); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LRJUMP); } else { if (phy->CurrentGrav == phy->Normal_Grav) player->setCurrentState(LJUMP); else if (phy->CurrentGrav == phy->Reverse_Grav) player->setCurrentState(ULJUMP); else if (phy->CurrentGrav == phy->Right_Grav) player->setCurrentState(RLJUMP); else if (phy->CurrentGrav == phy->Left_Grav) player->setCurrentState(LLJUMP); } player->setGrounded(false); } if (input->isKeyDownForFirstTime(P_KEY)) { game->getGSM()->getPhysics()->activated = !(game->getGSM()->getPhysics()->activated); } if (input->isKeyDownForFirstTime(R_KEY)) { game->getGSM()->levelResetTrigger = true; } // NOW SET THE ACTUAL PLAYER VELOCITY pp->setVelocity(vX, vY); // 0X43 is HEX FOR THE 'C' VIRTUAL KEY // THIS CHANGES THE CURSOR IMAGE if ((input->isKeyDownForFirstTime(C_KEY)) && input->isKeyDown(VK_SHIFT)) { Cursor *cursor = game->getGUI()->getCursor(); unsigned int id = cursor->getActiveCursorID(); id++; if (id == cursor->getNumCursorIDs()) id = 0; cursor->setActiveCursorID(id); } // LET'S MESS WITH THE TARGET FRAME RATE IF THE USER PRESSES THE HOME OR END KEYS WindowsTimer *timer = (WindowsTimer*)game->getTimer(); int fps = timer->getTargetFPS(); // THIS SPEEDS UP OUR GAME LOOP AND THUS THE GAME, NOTE THAT WE COULD ALTERNATIVELY SCALE // DOWN THE GAME LOGIC (LIKE ALL VELOCITIES) AS WE SPEED UP THE GAME. THAT COULD PROVIDE // A BETTER PLAYER EXPERIENCE if (input->isKeyDown(VK_HOME) && (fps < MAX_FPS)) timer->setTargetFPS(fps + FPS_INC); // THIS SLOWS DOWN OUR GAME LOOP, BUT WILL NOT GO BELOW 5 FRAMES PER SECOND else if (input->isKeyDown(VK_END) && (fps > MIN_FPS)) timer->setTargetFPS(fps - FPS_INC); } }
void Physics::getCollisionsSpriteSprite( World *world, CollidableObject *spriteA, CollidableObject *spriteB, float percentageOfFrameRemaining) { //vector<WorldLayer*> *layers = world->getLayers(); AABB *boundingVolumeA = spriteA->getBoundingVolume(); AABB *boundingVolumeB = spriteB->getBoundingVolume(); PhysicalProperties *ppA = spriteA->getPhysicalProperties(); PhysicalProperties *ppB = spriteB->getPhysicalProperties(); int centerXA = boundingVolumeA->getCenterX(); int centerXB = boundingVolumeB->getCenterX(); int centerYA = boundingVolumeA->getCenterY(); int centerYB = boundingVolumeB->getCenterY(); int widthA = boundingVolumeA->getWidth(); int widthB = boundingVolumeB->getWidth(); int heightA = boundingVolumeA->getHeight(); int heightB = boundingVolumeB->getHeight(); int vxA = ppA->getVelocityX(); int vxB = ppB->getVelocityX(); int vyA = ppA->getVelocityY(); int vyB = ppB->getVelocityY(); // A - B if ((centerXB - (widthB/2)) > (centerXA + (widthA/2))) { //if(!((vxA - vxB) == 0)) { // if(boundingVolumeA->overlapsX(boundingVolumeB)){ if(!((vxA - vxB) == 0)) { int tx_first_contact = abs(((centerXB - (widthB/2)) - (centerXA + (widthA/2)))/(vxA - vxB)); int tx_last_contact = abs(((centerXB + (widthB/2)) - (centerXA - (widthA/2)))/(vxA - vxB)); if(tx_first_contact > percentageOfFrameRemaining) { //there`s no collision } else { if(!(vyA - vyB) == 0) { //there`s contact on X axis, so let`s see if there`s contact on y axis int ty_first_contact = abs(((centerYB - (heightB/2)) - (centerYA + (heightA/2)))/(vyA - vyB)); //int ty_first_contact = boundingVolumeA->overlapsY(boundingVolumeB); int ty_last_contact = abs(((centerYB + (heightB/2)) - (centerYA - (heightA/2)))/(vyA - vyB)); if(ty_first_contact > percentageOfFrameRemaining) { //there`s no collision } else { //there`s collision! //add collision to vector addCollisionSpriteSprite(spriteA, spriteB); } } else { //none of them are not going anywhere up, so they must collide on x axis //if they collide on y //if(((centerYB + heightB/2) - (centerYA - heightA/2)) >= 0) if(boundingVolumeA->overlapsY(boundingVolumeB)) {addCollisionSpriteSprite(spriteA, spriteB);} } // } } } else { //the situation here is kind of special //they could be stopped in X, or they could be walking in the same velocity //in the second situation, we are cool because they wouldn`t collide anyway //in the firt situation, they could colide (one on top of the other) //because of this, we have to make sure that one is on top of the other //and that they can collide on y axis //boundingVolumeB->setWidth(boundingVolumeB->getWidth() *2); if(boundingVolumeA->myOverlapsX(boundingVolumeB))// && !(boundingVolumeA->overlapsY(boundingVolumeB))) { //boundingVolumeB->setWidth(boundingVolumeB->getWidth()/2); addCollisionSpriteSprite(spriteA, spriteB); } } } // B - A else { if(!((vxB - vxA) == 0)) { int tx_first_contact = abs(((centerXA - (widthA/2)) - (centerXB + (widthB/2)))/(vxB - vxA)); //int tx_first_contact = boundingVolumeB->overlapsX(boundingVolumeA); int tx_last_contact = abs(((centerXA + (widthA/2)) - (centerXB - (widthB/2)))/(vxB - vxA)); if(tx_first_contact > percentageOfFrameRemaining) { //there`s no collision } else { if(!(vyB - vyA) == 0) { //there`s contact on X axis, so let`s see if there`s contact on y axis int ty_first_contact = abs(((centerYA - (heightA/2)) - (centerYB + (heightB/2)))/(vyB - vyA)); //int ty_first_contact = boundingVolumeB->overlapsY(boundingVolumeA); int ty_last_contact = abs(((centerYA + (heightA/2)) - (centerYB - (heightB/2)))/(vyB - vyA)); if(ty_first_contact > percentageOfFrameRemaining) { //there`s no collision } else { //there`s collision! //add collision to vector addCollisionSpriteSprite(spriteA, spriteB); } } else { //none of them are not going anywhere up, so they must collide on x axis //if they collide on y //if(((centerYA - heightA/2) - (centerYB + heightB/2)) <= 0 ) if(boundingVolumeB->overlapsY(boundingVolumeA)) {addCollisionSpriteSprite(spriteA, spriteB);} } } } else { //there`s no movement , so they won`t collide // boundingVolumeA->setWidth(boundingVolumeA->getWidth() *2); if(boundingVolumeB->myOverlapsX(boundingVolumeA))//&& !(boundingVolumeB->overlapsY(boundingVolumeA))) { addCollisionSpriteSprite(spriteA, spriteB); } } } // physics->addTileCollision(dynamicObject, testTile, tileX, tileY, (float)tileWidth, (float)tileHeight); }