//////////////////////////KEEP///////////////////////////////////////////// void Physics::addCollidableObject(CollidableObject *collidableObjectToAdd) { PhysicalProperties *pp = collidableObjectToAdd->getPhysicalProperties(); float height = pixelsToMeters(collidableObjectToAdd->getBoundingVolume()->getHeight()) / 2; float width = pixelsToMeters(collidableObjectToAdd->getBoundingVolume()->getWidth()) / 2; float x = pixelsToMeters(pp->getX()); float y = pixelsToMeters(-pp->getY()); // Define the dynamic body. We set its position and call the body factory. b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(x, y); b2Body* body = box2DWorld->CreateBody(&bodyDef); testSubjectBody = body; // Define another box shape for our dynamic body. b2PolygonShape dynamicBox; dynamicBox.SetAsBox(width, height); // Define the dynamic body fixture. b2FixtureDef fixtureDef; fixtureDef.shape = &dynamicBox; // Set the box density to be non-zero, so it will be dynamic. fixtureDef.density = 1.0f; // Override the default friction. fixtureDef.friction = 0.3f; // Add the shape to the body. body->CreateFixture(&fixtureDef); }
/* 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; }
void WalkaboutMouseEventHandler::handleMousePressEvent(Game *game, int mouseX, int mouseY) { if (game->getGSM()->isGameInProgress()) { Viewport *viewport = game->getGUI()->getViewport(); // DETERMINE WHERE ON THE MAP WE HAVE CLICKED int worldCoordinateX = mouseX + viewport->getViewportX(); int worldCoordinateY = mouseY + viewport->getViewportY(); SpriteManager *spriteManager = game->getGSM()->getSpriteManager(); Player* player = static_cast<Player*>(spriteManager->getPlayer()); PhysicalProperties* playerPP = spriteManager->getPlayer()->getPhysicalProperties(); if(!player->getIsDead() && !player->getIsDying() && player->getAmmo() != 0) { float dx = worldCoordinateX - playerPP->getX(); float dy = worldCoordinateY - playerPP->getY(); float distanceToMouse = sqrtf(dx*dx + dy*dy); dx /= distanceToMouse; dy /= distanceToMouse; float bulletOffset = 60; float bulletSpeed = 50; //Fire projectile spriteManager->createProjectile(playerPP->getX() + bulletOffset*dx, playerPP->getY() + bulletOffset*dy, bulletSpeed*dx,bulletSpeed*dy); player->decrementAmmo(); } } }
/* 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());*/ }
void ScienceMouseEventHandler::handleMousePressEvent(Game *game, int mouseX, int mouseY) { if (game->getGSM()->isGameInProgress()) { Viewport *viewport = game->getGUI()->getViewport(); // DETERMINE WHERE ON THE MAP WE HAVE CLICKED int worldCoordinateX = mouseX + viewport->getViewportX(); int worldCoordinateY = mouseY + viewport->getViewportY(); // NOW LET'S SEE IF THERE IS A SPRITE THERE GameStateManager *gsm = game->getGSM(); SpriteManager *spriteManager = gsm->getSpriteManager(); // IF THERE IS NO SELECTED SPRITE LOOK FOR ONE if (!(spriteManager->getIsSpriteSelected())) { // IF THIS DOES NOT RETURN NULL THEN YOU FOUND A SPRITE AT THAT LOCATION if((spriteManager->getSpriteAt(worldCoordinateX, worldCoordinateY) != NULL)) { AnimatedSprite *selected = spriteManager->getSpriteAt(worldCoordinateX, worldCoordinateY); spriteManager->setIsSpriteSelected(true); } } else if (spriteManager->getSelectedSprite() != NULL) { // MOVE A SPRITE IN A DESIRED DIRECTION AnimatedSprite *selected = spriteManager->getSelectedSprite(); PhysicalProperties *pp = selected->getPhysicalProperties(); float spriteX = pp->getX(); float spriteY = pp->getY(); //IF A SPRITE IS WHERE YOU WANT IT THEN STOP IT if (((spriteX > worldCoordinateX - 64) && (spriteX < worldCoordinateX + 64)) && (spriteY > worldCoordinateY - 64) && (spriteY < worldCoordinateY + 64)) { pp->setVelocity(0, 0); } else { float deltaX = worldCoordinateX - spriteX; float deltaY = worldCoordinateY - spriteY; float hyp = sqrtf((deltaX * deltaX) + (deltaY * deltaY)); pp->setVelocity((deltaX / hyp) * 3, (deltaY / hyp) * 3); } spriteManager->setIsSpriteSelected(false); // GridPathfinder *pathfinder = spriteManager->getPathfinder(); // pathfinder->mapPath(selected, (float)worldCoordinateX, (float)worldCoordinateY); // gsm->setSpriteSelected(false, selected); } else { spriteManager->setIsSpriteSelected(false); } } }
/* addSpriteToRenderList - This method checks to see if the sprite parameter is inside the viewport. If it is, a RenderItem is generated for that sprite and it is added to the render list. */ void SpriteManager::addSpriteToRenderList(AnimatedSprite *sprite, RenderList *renderList, Viewport *viewport) { // GET THE SPRITE TYPE INFO FOR THIS SPRITE AnimatedSpriteType *spriteType = sprite->getSpriteType(); PhysicalProperties *pp = sprite->getPhysicalProperties(); // IS THE SPRITE VIEWABLE? if (viewport->areWorldCoordinatesInViewport( pp->getX(), pp->getY(), spriteType->getTextureWidth(), spriteType->getTextureHeight())) { // SINCE IT'S VIEWABLE, ADD IT TO THE RENDER LIST RenderItem itemToAdd; itemToAdd.id = sprite->getFrameIndex(); renderList->addRenderItem( sprite->getCurrentImageID(), /*sprite->body->GetPosition().x*/ pp->round(pp->getX()-viewport->getViewportX()), /*sprite->body->GetPosition().y*/ pp->round(pp->getY() - viewport->getViewportY()), pp->round(pp->getZ()), sprite->getAlpha(), spriteType->getTextureWidth(), spriteType->getTextureHeight(), sprite->getRotationInRadians()); } }
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; }
/* 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 BotSpawningPool::update() { countdownCounter--; if (countdownCounter <= 0) { // SPAWN A BOT Game *game = Game::getSingleton(); GameStateManager *gsm = game->getGSM(); SpriteManager *spriteManager = gsm->getSpriteManager(); BotRecycler *botRecycler = spriteManager->getBotRecycler(); Bot *spawnedBot = botRecycler->retrieveBot(botType); spriteManager->addBot(spawnedBot); initCountdownCounter(); // DO IT'S SPAWNING BEHAVIOR BotBehavior *spawningBehavior = spawnedBot->getBehavior(BotState::SPAWNING); spawningBehavior->behave(spawnedBot); // AND START IT LOCATED AT THE SPAWNING POOL PhysicalProperties *pp = spawnedBot->getPhysicalProperties(); pp->setX(x); pp->setY(y); } }
/* 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; }
/* clone - this method makes another BackAndForthBot object, but does not completely initialize it with similar data to this. Most of the object, like velocity and position, are left uninitialized. */ Bot* BackAndForthBot::clone() { BackAndForthBot *botClone = new BackAndForthBot(); PhysicalProperties* pp = this->getPhysicalProperties(); PhysicalProperties* bp = botClone->getPhysicalProperties(); BoundingVolume* pV = this->getBoundingVolume(); BoundingVolume* bV = botClone->getBoundingVolume(); botClone->setEnemy(enemy); botClone->setItem(item); botClone->setPortal(portal); botClone->setSpriteType(this->getSpriteType()); botClone->setAlpha(this->getAlpha()); botClone->setDead(false); bp->setCollidable(pp->isCollidable()); bp->setGravAffected(pp->isGravAffected()); bV->setHeight(pV->getHeight()); bV->setWidth(pV->getWidth()); bV->setX(pV->getX()); bV->setY(pV->getY()); return botClone; }
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); } }
/* 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); }
void SpriteManager::addSpriteToRenderList(AnimatedSprite *sprite, RenderList *renderList, Viewport *viewport) { // GET THE SPRITE TYPE INFO FOR THIS SPRITE AnimatedSpriteType *spriteType = sprite->getSpriteType(); PhysicalProperties *pp = sprite->getPhysicalProperties(); if (i >= 3) { b2Body* bods= sprite->getBody(); b2Vec2 position = bods->GetPosition(); pp->setX(position.x); pp->setY(position.y); } i+=1; // IS THE SPRITE VIEWABLE? if (viewport->areWorldCoordinatesInViewport( pp->getX(), pp->getY(), spriteType->getTextureWidth(), spriteType->getTextureHeight()) ) { // SINCE IT'S VIEWABLE, ADD IT TO THE RENDER LIST RenderItem itemToAdd; itemToAdd.id = sprite->getFrameIndex(); if (spriteType->getTextureWidth()==61) { renderList->addRenderItem( sprite->getCurrentImageID(), pp->round(X-viewport->getViewportX()), pp->round(Y-25-viewport->getViewportY()), pp->round(pp->getZ()), sprite->getAlpha(), spriteType->getTextureWidth(), spriteType->getTextureHeight()); } else { renderList->addRenderItem( sprite->getCurrentImageID(), pp->round(pp->getX()-viewport->getViewportX()), pp->round(pp->getY()-viewport->getViewportY()), pp->round(pp->getZ()), sprite->getAlpha(), spriteType->getTextureWidth(), spriteType->getTextureHeight()); } } }
/* 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(); }
/* 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 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++; }*/ }
/* 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::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 BossBot::update(Game *game){ //////////////////////// /////////////////////// /////////////////////// if(dead) { return; } // If hitpoints are 0, remove it if(hitPoints <= 0){ setCurrentState(direction==1?DYING_RIGHT:DYING_LEFT); game->getGSM()->getSpriteManager()->addBotToRemovalList(this, 15); dead = true; game->getGSM()->goToLevelWon(); return; } // Decrement frames since last attack cooldownCounter--; if(getCurrentState()==ATTACKING_RIGHT||getCurrentState()==ATTACKING_LEFT){ if(this->getFrameIndex()==10) setCurrentState(direction==1?IDLE_RIGHT:IDLE_LEFT); } // If can attack, check if player in range. if(cooldownCounter <= 0){ // If player is next to this bot, do something different int botX = getCurrentBodyX() * BOX2D_CONVERSION_FACTOR; int pX = game->getGSM()->getSpriteManager()->getPlayer()->getCurrentBodyX() * BOX2D_CONVERSION_FACTOR; // If the player is within the bots targeting area, go after the player if(isInBounds(pX)) { int botY = getCurrentBodyY() * BOX2D_CONVERSION_FACTOR; int pY = game->getGSM()->getSpriteManager()->getPlayer()->getCurrentBodyY() * BOX2D_CONVERSION_FACTOR; // Make sure the player is in the same y area if(std::abs(botY - pY) < 200){ if (pX<botX) direction=-1; else direction=1; cooldownCounter = attackCooldown; this->setCurrentState(direction==1?ATTACKING_RIGHT:ATTACKING_LEFT); // Seed AnimatedSpriteType *seedSpriteType = game->getGSM()->getSpriteManager()->getSpriteType(3); Seed *seed = new Seed(PROJECTILE_DESIGNATION, true); seed->setHitPoints(1); seed->setDamage(SEED_DAMAGE); seed->setSpriteType(seedSpriteType); seed->setAlpha(255); seed->setCurrentState(IDLE_LEFT); PhysicalProperties *seedProps = seed->getPhysicalProperties(); seedProps->setX(botX); seedProps->setY(game->getGSM()->getWorld()->getWorldHeight() - botY); seedProps->setVelocity(0.0f, 0.0f); seedProps->setAccelerationX(0); seedProps->setAccelerationY(0); seed->setOnTileThisFrame(false); seed->setOnTileLastFrame(false); seed->affixTightAABBBoundingVolume(); //create a physics object for the seed game->getGSM()->getBoxPhysics()->getPhysicsFactory()->createEnemyObject(game,seed,false); float difX = botX - pX; float difY = botY - pY; // Set the velocity of the seed float length = std::sqrt( (difX * difX) + (difY * difY) ); // Normalize the distances difX /= length; difY /= length; // Scale distances to be x and y velocity difX *= PROJECTILE_VELOCITY; difY = difY*PROJECTILE_VELOCITY-10; seed->getPhysicsBody()->SetLinearVelocity(b2Vec2(-difX, -difY)); game->getGSM()->getPhysics()->addCollidableObject(seed); game->getGSM()->getSpriteManager()->addBot(seed); } } } ////////////////////// /////////////////////// /////////////////////// /* if(dead) { return; } // If hitpoints are 0, remove it if(hitPoints <= 0){ game->getGSM()->goToLevelWon(); game->getGSM()->getSpriteManager()->addBotToRemovalList(this, 0); dead = true; return; } // Decrement frames since last attack cooldownCounter--; // If can attack, check if player in range. if(cooldownCounter <= 0){ // If player is next to this bot, do something different int botX = getCurrentBodyX() * BOX2D_CONVERSION_FACTOR; int pX = game->getGSM()->getSpriteManager()->getPlayer()->getCurrentBodyX() * BOX2D_CONVERSION_FACTOR; // If the player is within the bots targeting area, go after the player if(isInBounds(pX)) { int botY = getCurrentBodyY() * BOX2D_CONVERSION_FACTOR; int pY = game->getGSM()->getSpriteManager()->getPlayer()->getCurrentBodyY() * BOX2D_CONVERSION_FACTOR; // Make sure the player is in the same y area if(std::abs(botY - pY) < 200){ cooldownCounter = attackCooldown; // Seed AnimatedSpriteType *seedSpriteType = game->getGSM()->getSpriteManager()->getSpriteType(3); Seed *seed = new Seed(PROJECTILE_DESIGNATION, true); seed->setHitPoints(1); seed->setDamage(SEED_DAMAGE); seed->setSpriteType(seedSpriteType); seed->setAlpha(255); seed->setCurrentState(IDLE_LEFT); PhysicalProperties *seedProps = seed->getPhysicalProperties(); seedProps->setX(botX); seedProps->setY(game->getGSM()->getWorld()->getWorldHeight() - botY); seedProps->setVelocity(0.0f, 0.0f); seedProps->setAccelerationX(0); seedProps->setAccelerationY(0); seed->setOnTileThisFrame(false); seed->setOnTileLastFrame(false); seed->affixTightAABBBoundingVolume(); //create a physics object for the seed game->getGSM()->getBoxPhysics()->getPhysicsFactory()->createEnemyObject(game,seed,true); // Set the velocity of the seed seed->getPhysicsBody()->SetLinearVelocity(b2Vec2(attackSpeed, 0.5)); game->getGSM()->getPhysics()->addCollidableObject(seed); game->getGSM()->getSpriteManager()->addBot(seed); } } } */ }
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::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); }