void World::update(int ticks) { removeDeadObjects(mRenderables); removeDeadObjects(mCollideables); mPlayer->update(); if (!mPlayer->isAlive()) { mPlayer->respawn(mSpawnPoint); mCollideables.push_back(mPlayer); } for (auto& obj : mCollideables) { obj->update(); if (!obj->isStatic()) obj->setVelocity(obj->getVelocity() + mGravity*(UPDATE_STEP.asSeconds())); if (obj->getPhysicsPosition().y > SCREEN_HEIGHT) obj->kill(); } for (auto& obj : mRenderables) { if (obj->isParallaxable()) { obj->setRenderPosition(obj->getRenderPosition() + sf::Vector2f(0.25f, 0.f)); if (obj->getRenderPosition().x > SCREEN_WIDTH) obj->setRenderPosition(sf::Vector2f(-obj->getSpriteInfo().mHitBox.width, obj->getRenderPosition().y)); } } // check collisions for (std::size_t x = 0; x < mCollideables.size(); x++) { for (std::size_t y = x+1; y < mCollideables.size(); y++) { auto dynamic = mCollideables[x]; auto _static = mCollideables[y]; if (!mCollideables[x]->isStatic()) dynamic = mCollideables[x]; else if (!mCollideables[y]->isStatic()) dynamic = mCollideables[y]; if (mCollideables[x]->isStatic()) _static = mCollideables[x]; else if (mCollideables[y]->isStatic()) _static = mCollideables[y]; if (dynamic != _static) { if (checkCollision(dynamic, _static) && dynamic->isCollisionActive() && _static->isCollisionActive()) resolveCollision(dynamic, _static); } } } mCamera.follow(sf::Vector2f(mPlayer->getRenderPosition().x, SCREEN_HEIGHT/2.f)); }
void Figure::xMovement(vector<Figure*>& other, int deltaTicks) { int count = 0; p.x += v.x * deltaTicks / 1000.0; if (isCollided(other, count) && count != -1) resolveCollision(other[count], deltaTicks, XHAT); else if (p.x > lw - dim.w) p.x = lw - dim.w; else if (p.x < 0) p.x = 0; }
void Sim::collide() { contact->circle = ball; for (int i = 0; i < 4; i++) { if (inside(red[i].position.x - 1000, red[i].position.x + 1000, ball->position.x)) { for (int j = 0; j < red[i].size; j++) { contact->axis = red[i]; contact->player = j; if (AABBvsCircle(contact)) resolveCollision(contact); } } if (inside(blu[i].position.x - 1000, blu[i].position.x + 1000, ball->position.x)) { for (int j = 0; j < blu[i].size; j++) { contact->axis = blu[i]; contact->player = j; if (AABBvsCircle(contact)) resolveCollision(contact); } } } contactboundary->circle = ball; for (int i = 0; i < 6; i++) { contactboundary->box = &boundary[i]; if (boundaryVsCircle(contactboundary)) resolveCollisionBoundary(contactboundary); } }
void PlayerFigure::xMovement(vector<Figure*>& other, int deltaTicks) { int count = 0; //x movement grabstate determineGrabX(deltaTicks); p.x += (v.x * deltaTicks / 1000.0) + grabVel.x; if (isCollided(other, count) && count != -1) resolveCollision(other[count], deltaTicks, XHAT); else if (p.x > lw - dim.w) p.x = lw - dim.w; else if (p.x < 0) p.x = 0; }
int main() { printf("Enter Time Limit : "); scanf("%f",&TIME_LIMIT); int i, j; srand(time(NULL)); Heap *heap; Ball **ball; Interaction *nextCollision; heap = initHeap(); ball = (Ball **)malloc(PARTICLE_COUNT * sizeof(Ball *)); gnuplotPipe = initPipe(); for(i = 0; i < PARTICLE_COUNT; i++) { logFile[i] = initGraph(i); gnuplotGraphPipe[i] = initGraphPipe(i); } for(i = 0; i < PARTICLE_COUNT; i++) { ball[i] = initBallRandom(i); insertToHeap(heap, eventWallCollideX(heap, ball[i])); insertToHeap(heap, eventWallCollideY(heap, ball[i])); for(j = 0; j < i; j++) insertToHeap(heap, eventBallCollide(heap, ball[i], ball[j])); } while(sim_time < TIME_LIMIT) { nextCollision = getNextEvent(heap); simulateTo(ball, nextCollision->tstamp); printf("Collision at t=%lf\n", sim_time); resolveCollision(nextCollision); removeFromHeap(heap, nextCollision->interactee->id); scheduleEvent(ball, heap, nextCollision->interactee->id); if(nextCollision->interactor != NULL) { removeFromHeap(heap, nextCollision->interactor->id); scheduleEvent(ball, heap, nextCollision->interactor->id); } } fprintf(gnuplotPipe, "quit\n"); saveGraph(ball); showGraph(ball); return 0; }
void ParticleSystemSolver2::onAdvanceTimeStep(double timeStepInSeconds) { beginAdvanceTimeStep(timeStepInSeconds); Timer timer; accumulateForces(timeStepInSeconds); JET_INFO << "Accumulating forces took " << timer.durationInSeconds() << " seconds"; timer.reset(); timeIntegration(timeStepInSeconds); JET_INFO << "Time integration took " << timer.durationInSeconds() << " seconds"; timer.reset(); resolveCollision(); JET_INFO << "Resolving collision took " << timer.durationInSeconds() << " seconds"; endAdvanceTimeStep(timeStepInSeconds); }
void Figure::yMovement(vector<Figure*>& other, int deltaTicks) { int count = 0; //gravity considerations determineGravity(); //jump action determineJump(); //check if inAir is true checkIfInAir(other); //collision with boundaries or other Figures p.y += v.y * deltaTicks / 1000.0; if (isCollided(other, count) && count != -1) { resolveCollision(other[count], deltaTicks, YHAT); } else if (p.y > lh - dim.h) p.y = lh - dim.h; }
void ParticleSystemSolver2::resolveCollision() { resolveCollision( _newPositions.accessor(), _newVelocities.accessor()); }
virtual void stepSimulation(float deltaTime) { switch (m_tutorialIndex) { case TUT_VELOCITY: { tutorial1Update(deltaTime); float xPos = m_bodies[0]->m_worldPose.m_position.x; float xVel = m_bodies[0]->m_linearVelocity.x; m_timeSeriesCanvas0->insertDataAtCurrentTime(xPos,0,true); m_timeSeriesCanvas0->insertDataAtCurrentTime(xVel,1,true); break; } case TUT_ACCELERATION: { tutorial2Update(deltaTime); float yPos = m_bodies[0]->m_worldPose.m_position.y; float yVel = m_bodies[0]->m_linearVelocity.y; m_timeSeriesCanvas1->insertDataAtCurrentTime(yPos,0,true); m_timeSeriesCanvas1->insertDataAtCurrentTime(yVel,1,true); break; } case TUT_COLLISION: { m_contactPoints.clear(); LWContactPoint contactPoint; tutorialCollisionUpdate(deltaTime, contactPoint); m_contactPoints.push_back(contactPoint); m_timeSeriesCanvas1->insertDataAtCurrentTime(contactPoint.m_distance,0,true); break; } case TUT_SOLVE_CONTACT_CONSTRAINT: { m_contactPoints.clear(); LWContactPoint contactPoint; tutorialSolveContactConstraintUpdate(deltaTime, contactPoint); m_contactPoints.push_back(contactPoint); if (contactPoint.m_distance<0) { m_bodies[0]->computeInvInertiaTensorWorld(); m_bodies[1]->computeInvInertiaTensorWorld(); b3Scalar appliedImpulse = resolveCollision(*m_bodies[0], *m_bodies[1], contactPoint ); m_timeSeriesCanvas1->insertDataAtCurrentTime(appliedImpulse,1,true); } else { m_timeSeriesCanvas1->insertDataAtCurrentTime(0.,1,true); } m_timeSeriesCanvas1->insertDataAtCurrentTime(contactPoint.m_distance,0,true); break; } default: { } }; if (m_timeSeriesCanvas0) m_timeSeriesCanvas0->nextTick(); if (m_timeSeriesCanvas1) m_timeSeriesCanvas1->nextTick(); for (int i=0;i<m_bodies.size();i++) { m_bodies[i]->integrateAcceleration(deltaTime); m_bodies[i]->integrateVelocity(deltaTime); m_app->m_renderer->writeSingleInstanceTransformToCPU(m_bodies[i]->m_worldPose.m_position, m_bodies[i]->m_worldPose.m_orientation, m_bodies[i]->m_graphicsIndex); } m_app->m_renderer->writeTransforms(); }
void StdChoreographer::update(double dt) { _dt = dt; if(_dt == 0) { // No time elapsed, // no need to update return; } if(_dt > _maxHandledDeltaTime) { // To much time elpased, // would make the simulation unstable return; } size_t nbCircles = _circles.size(); size_t nbPolygons = _polygons.size(); // Update positions of all shapes for(size_t i=0; i<_circles.size(); ++i) { updateShape(_circles[i]); } for(size_t i=0; i<_polygons.size(); ++i) { updateShape(_polygons[i]); } // Resolve collisions of dynamic shapes // Order is important; // A shape should never trigger a resolveXY() with a preceding shape : // * Circles precede Polygons // * Lower indices precede higher indices std::vector< std::shared_ptr<StdCollisionReport> > collisionReports; std::shared_ptr<StdCollisionReport> report; for(size_t master=0; master < nbCircles; ++master) { shared_ptr<Circle>& masterCircle = _circles[master]; if(masterCircle->bodyType() == EBodyType::DYNAMIC) { for(size_t slave = 0; slave < nbCircles; ++slave) { const std::shared_ptr<Circle>& slaveCircle = _circles[slave]; if(slaveCircle->bodyType() != EBodyType::GRAPHIC && (slaveCircle->bodyType() == EBodyType::KINEMATIC || master < slave)) { report = detectCircleCircle(masterCircle, slaveCircle); if(report->areColliding) collisionReports.push_back(report); } } for(size_t slave = 0; slave < nbPolygons; ++slave) { const std::shared_ptr<Polygon>& slavePolygon = _polygons[slave]; if(slavePolygon->bodyType() != EBodyType::GRAPHIC) { report = detectCirclePolygon(masterCircle, slavePolygon); if(report->areColliding) collisionReports.push_back(report); } } } } for(size_t master=0; master < nbPolygons; ++master) { shared_ptr<Polygon>& masterPolygon = _polygons[master]; if(masterPolygon->bodyType() == EBodyType::DYNAMIC) { for(size_t slave = 0; slave < nbCircles; ++slave) { const std::shared_ptr<Circle>& slaveCircle = _circles[slave]; if(slaveCircle->bodyType() == EBodyType::KINEMATIC) { report = detectCirclePolygon(slaveCircle, masterPolygon); if(report->areColliding) collisionReports.push_back(report); } } for(size_t slave = 0; slave < nbPolygons; ++slave) { const std::shared_ptr<Polygon>& slavePolygon = _polygons[slave]; if(slavePolygon->bodyType() != EBodyType::GRAPHIC && (slavePolygon->bodyType() == EBodyType::KINEMATIC || master < slave)) { report = detectPolygonPolygon(masterPolygon, slavePolygon); if(report->areColliding) collisionReports.push_back(report); } } } } // Resolve found collisions int nbReports = static_cast<int>(collisionReports.size()); for(int i=0; i < nbReports; ++i) { moveApart(collisionReports[i]); resolveCollision(collisionReports[i]); } }
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 GameStatePlayUpdate(void) { if (AEInputCheckTriggered(DIK_J)) SendJoinMessage(); MsgInput inputMsg; if(ProcInput(inputMsg)) { strcpy(inputMsg.data_.username_.name_, client.config_.username_.c_str()); NetworkMessage netMsg; netMsg << inputMsg; netMsg.receiverAddress_ = client.remoteAddr_; try { printf("\nSending INPUT message... Input Count = %d\n", inputMsg.data_.key_info_count_); client.udpSock_.Send(netMsg); } catch(iSocket::SockErr& e) { e.Print(); } } char buffer[1000] = { 0 }; sprintf(buffer, "TIME LEFT: %.2f", time); AEGfxPrint(300, 10, 0xFFFFFFFF, buffer); sprintf(buffer, "Round: %u", round); AEGfxPrint(350, 30, 0xFFFFFFFF, buffer); unsigned yPos = 10; unsigned xPos = 10; for(std::vector<ResultStatus>::iterator it = results.begin(); it != results.end(); ++it) { sprintf(buffer, "%s: Score: %u", it->name_.name_, it->score_); AEGfxPrint(xPos, yPos, 0xFFFFFFFF, buffer); yPos += ROW_HEIGHT; } client.udpSock_.Resend(); // check for messages from server NetworkMessage netMsg; if(client.udpSock_.Receive(netMsg)) ProcMessage(netMsg); #if 0 // =============== // update physics // =============== for (u32 i = 0; i < GAME_OBJ_INST_NUM_MAX; i++) { GameObjInst* pInst = sGameObjInstList + i; // skip non-active object if ((pInst->flag & FLAG_ACTIVE) == 0) continue; // update the position AEVec2ScaleAdd(&pInst->posCurr, &pInst->velCurr, &pInst->posCurr, (f32)(gAEFrameTime)); } // =============== // update objects // =============== for (u32 i = 0; i < GAME_OBJ_INST_NUM_MAX; i++) { GameObjInst* pInst = sGameObjInstList + i; // skip non-active object if ((pInst->flag & FLAG_ACTIVE) == 0) continue; // check if the object is a ship if (pInst->pObject->type == TYPE_SHIP) { // warp the ship from one end of the screen to the other pInst->posCurr.x = AEWrap(pInst->posCurr.x, gAEWinMinX - SHIP_SIZE, gAEWinMaxX + SHIP_SIZE); pInst->posCurr.y = AEWrap(pInst->posCurr.y, gAEWinMinY - SHIP_SIZE, gAEWinMaxY + SHIP_SIZE); } // check if the object is an asteroid else if (pInst->pObject->type == TYPE_ASTEROID) { AEVec2 u; f32 uLen; // warp the asteroid from one end of the screen to the other pInst->posCurr.x = AEWrap(pInst->posCurr.x, gAEWinMinX - AST_SIZE_MAX, gAEWinMaxX + AST_SIZE_MAX); pInst->posCurr.y = AEWrap(pInst->posCurr.y, gAEWinMinY - AST_SIZE_MAX, gAEWinMaxY + AST_SIZE_MAX); // pull the asteroid toward the ship a little bit if (spShip) { // apply acceleration propotional to the distance from the asteroid to the ship AEVec2Sub (&u, &spShip->posCurr, &pInst->posCurr); AEVec2Scale (&u, &u, AST_TO_SHIP_ACC * (f32)(gAEFrameTime)); AEVec2Add (&pInst->velCurr, &pInst->velCurr, &u); } // if the asterid velocity is more than its maximum velocity, reduce its speed if ((uLen = AEVec2Length(&pInst->velCurr)) > (AST_VEL_MAX * 2.0f)) { AEVec2Scale (&u, &pInst->velCurr, (1.0f / uLen) * (AST_VEL_MAX * 2.0f - uLen) * pow(AST_VEL_DAMP, (f32)(gAEFrameTime))); AEVec2Add (&pInst->velCurr, &pInst->velCurr, &u); } } // check if the object is a bullet else if (pInst->pObject->type == TYPE_BULLET) { // kill the bullet if it gets out of the screen if (!AEInRange(pInst->posCurr.x, gAEWinMinX - AST_SIZE_MAX, gAEWinMaxX + AST_SIZE_MAX) || !AEInRange(pInst->posCurr.y, gAEWinMinY - AST_SIZE_MAX, gAEWinMaxY + AST_SIZE_MAX)) gameObjInstDestroy(pInst); } // check if the object is a bomb else if (pInst->pObject->type == TYPE_BOMB) { // adjust the life counter pInst->life -= (f32)(gAEFrameTime) / BOMB_LIFE; if (pInst->life < 0.0f) { gameObjInstDestroy(pInst); } else { f32 radius = 1.0f - pInst->life; AEVec2 u; pInst->dirCurr += 2.0f * PI * (f32)(gAEFrameTime); radius = 1.0f - radius; radius *= radius; radius *= radius; radius *= radius; radius *= radius; radius = (1.0f - radius) * BOMB_RADIUS; // generate the particle ring for (u32 j = 0; j < 10; j++) { //f32 dir = AERandFloat() * 2.0f * PI; f32 dir = (j / 9.0f) * 2.0f * PI + pInst->life * 1.5f * 2.0f * PI; u.x = AECos(dir) * radius + pInst->posCurr.x; u.y = AESin(dir) * radius + pInst->posCurr.y; //sparkCreate(PTCL_EXHAUST, &u, 1, dir + 0.8f * PI, dir + 0.9f * PI); sparkCreate(PTCL_EXHAUST, &u, 1, dir + 0.40f * PI, dir + 0.60f * PI); } } } // check if the object is a missile else if (pInst->pObject->type == TYPE_MISSILE) { // adjust the life counter pInst->life -= (f32)(gAEFrameTime) / MISSILE_LIFE; if (pInst->life < 0.0f) { gameObjInstDestroy(pInst); } else { AEVec2 dir; if (pInst->pUserData == 0) { pInst->pUserData = missileAcquireTarget(pInst); } else { GameObjInst* pTarget = (GameObjInst*)(pInst->pUserData); // if the target is no longer valid, reacquire if (((pTarget->flag & FLAG_ACTIVE) == 0) || (pTarget->pObject->type != TYPE_ASTEROID)) pInst->pUserData = missileAcquireTarget(pInst); } if (pInst->pUserData) { GameObjInst* pTarget = (GameObjInst*)(pInst->pUserData); AEVec2 u; f32 uLen; // get the vector from the missile to the target and its length AEVec2Sub(&u, &pTarget->posCurr, &pInst->posCurr); uLen = AEVec2Length(&u); // if the missile is 'close' to target, do nothing if (uLen > 0.1f) { // normalize the vector from the missile to the target AEVec2Scale(&u, &u, 1.0f / uLen); // calculate the missile direction vector AEVec2Set(&dir, AECos(pInst->dirCurr), AESin(pInst->dirCurr)); // calculate the cos and sin of the angle between the target // vector and the missile direction vector f32 cosAngle = AEVec2DotProduct(&dir, &u), sinAngle = AEVec2CrossProductMag(&dir, &u), rotAngle; // calculate how much to rotate the missile if (cosAngle < AECos(MISSILE_TURN_SPEED * (f32)(gAEFrameTime))) rotAngle = MISSILE_TURN_SPEED * (f32)(gAEFrameTime); else rotAngle = AEACos(AEClamp(cosAngle, -1.0f, 1.0f)); // rotate to the left if sine of the angle is positive and vice versa pInst->dirCurr += (sinAngle > 0.0f) ? rotAngle : -rotAngle; } } // adjust the missile velocity AEVec2Set (&dir, AECos(pInst->dirCurr), AESin(pInst->dirCurr)); AEVec2Scale(&dir, &dir, MISSILE_ACCEL * (f32)(gAEFrameTime)); AEVec2Add (&pInst->velCurr, &pInst->velCurr, &dir); AEVec2Scale(&pInst->velCurr, &pInst->velCurr, pow(MISSILE_DAMP, (f32)(gAEFrameTime))); sparkCreate(PTCL_EXHAUST, &pInst->posCurr, 1, pInst->dirCurr + 0.8f * PI, pInst->dirCurr + 1.2f * PI); } } // check if the object is a particle else if ((TYPE_PTCL_WHITE <= pInst->pObject->type) && (pInst->pObject->type <= TYPE_PTCL_RED)) { pInst->scale *= pow(PTCL_SCALE_DAMP, (f32)(gAEFrameTime)); pInst->dirCurr += 0.1f; AEVec2Scale(&pInst->velCurr, &pInst->velCurr, pow(PTCL_VEL_DAMP, (f32)(gAEFrameTime))); if (pInst->scale < PTCL_SCALE_DAMP) gameObjInstDestroy(pInst); } } // ==================== // check for collision // ==================== for (u32 i = 0; i < GAME_OBJ_INST_NUM_MAX; i++) { GameObjInst* pSrc = sGameObjInstList + i; // skip non-active object if ((pSrc->flag & FLAG_ACTIVE) == 0) continue; if ((pSrc->pObject->type == TYPE_BULLET) || (pSrc->pObject->type == TYPE_MISSILE)) { for (u32 j = 0; j < GAME_OBJ_INST_NUM_MAX; j++) { GameObjInst* pDst = sGameObjInstList + j; // skip no-active and non-asteroid object if (((pDst->flag & FLAG_ACTIVE) == 0) || (pDst->pObject->type != TYPE_ASTEROID)) continue; if (AETestPointToRect(&pSrc->posCurr, &pDst->posCurr, pDst->scale, pDst->scale) == false) continue; if (pDst->scale < AST_SIZE_MIN) { sparkCreate(PTCL_EXPLOSION_M, &pDst->posCurr, (u32)(pDst->scale * 10), pSrc->dirCurr - 0.05f * PI, pSrc->dirCurr + 0.05f * PI, pDst->scale); sScore++; if ((sScore % AST_SPECIAL_RATIO) == 0) sSpecialCtr++; if ((sScore % AST_SHIP_RATIO) == 0) sShipCtr++; if (sScore == sAstNum * 5) sAstNum = (sAstNum < AST_NUM_MAX) ? (sAstNum * 2) : sAstNum; // destroy the asteroid gameObjInstDestroy(pDst); } else { sparkCreate(PTCL_EXPLOSION_S, &pSrc->posCurr, 10, pSrc->dirCurr + 0.9f * PI, pSrc->dirCurr + 1.1f * PI); // impart some of the bullet/missile velocity to the asteroid AEVec2Scale(&pSrc->velCurr, &pSrc->velCurr, 0.01f * (1.0f - pDst->scale / AST_SIZE_MAX)); AEVec2Add (&pDst->velCurr, &pDst->velCurr, &pSrc->velCurr); // split the asteroid to 4 if ((pSrc->pObject->type == TYPE_MISSILE) || ((pDst->life -= 1.0f) < 0.0f)) astCreate(pDst); } // destroy the bullet gameObjInstDestroy(pSrc); break; } } else if (TYPE_BOMB == pSrc->pObject->type) { f32 radius = 1.0f - pSrc->life; pSrc->dirCurr += 2.0f * PI * (f32)(gAEFrameTime); radius = 1.0f - radius; radius *= radius; radius *= radius; radius *= radius; radius *= radius; radius *= radius; radius = (1.0f - radius) * BOMB_RADIUS; // check collision for (u32 j = 0; j < GAME_OBJ_INST_NUM_MAX; j++) { GameObjInst* pDst = sGameObjInstList + j; if (((pDst->flag & FLAG_ACTIVE) == 0) || (pDst->pObject->type != TYPE_ASTEROID)) continue; if (AECalcDistPointToRect(&pSrc->posCurr, &pDst->posCurr, pDst->scale, pDst->scale) > radius) continue; if (pDst->scale < AST_SIZE_MIN) { f32 dir = atan2f(pDst->posCurr.y - pSrc->posCurr.y, pDst->posCurr.x - pSrc->posCurr.x); gameObjInstDestroy(pDst); sparkCreate(PTCL_EXPLOSION_M, &pDst->posCurr, 20, dir + 0.4f * PI, dir + 0.45f * PI); sScore++; if ((sScore % AST_SPECIAL_RATIO) == 0) sSpecialCtr++; if ((sScore % AST_SHIP_RATIO) == 0) sShipCtr++; if (sScore == sAstNum * 5) sAstNum = (sAstNum < AST_NUM_MAX) ? (sAstNum * 2) : sAstNum; } else { // split the asteroid to 4 astCreate(pDst); } } } else if (pSrc->pObject->type == TYPE_ASTEROID) { for (u32 j = 0; j < GAME_OBJ_INST_NUM_MAX; j++) { GameObjInst* pDst = sGameObjInstList + j; f32 d; AEVec2 nrm, u; // skip no-active and non-asteroid object if ((pSrc == pDst) || ((pDst->flag & FLAG_ACTIVE) == 0) || (pDst->pObject->type != TYPE_ASTEROID)) continue; // check if the object rectangle overlap d = AECalcDistRectToRect( &pSrc->posCurr, pSrc->scale, pSrc->scale, &pDst->posCurr, pDst->scale, pDst->scale, &nrm); if (d >= 0.0f) continue; // adjust object position so that they do not overlap AEVec2Scale (&u, &nrm, d * 0.25f); AEVec2Sub (&pSrc->posCurr, &pSrc->posCurr, &u); AEVec2Add (&pDst->posCurr, &pDst->posCurr, &u); // calculate new object velocities resolveCollision(pSrc, pDst, &nrm); } } else if (pSrc->pObject->type == TYPE_SHIP) { for (u32 j = 0; j < GAME_OBJ_INST_NUM_MAX; j++) { GameObjInst* pDst = sGameObjInstList + j; // skip no-active and non-asteroid object if ((pSrc == pDst) || ((pDst->flag & FLAG_ACTIVE) == 0) || (pDst->pObject->type != TYPE_ASTEROID)) continue; // check if the object rectangle overlap if (AETestRectToRect( &pSrc->posCurr, pSrc->scale, pSrc->scale, &pDst->posCurr, pDst->scale, pDst->scale) == false) continue; // create the big explosion sparkCreate(PTCL_EXPLOSION_L, &pSrc->posCurr, 100, 0.0f, 2.0f * PI); // reset the ship position and direction AEVec2Zero(&spShip->posCurr); AEVec2Zero(&spShip->velCurr); spShip->dirCurr = 0.0f; sSpecialCtr = SHIP_SPECIAL_NUM; // destroy all asteroid near the ship so that you do not die as soon as the ship reappear for (u32 j = 0; j < GAME_OBJ_INST_NUM_MAX; j++) { GameObjInst* pInst = sGameObjInstList + j; AEVec2 u; // skip no-active and non-asteroid object if (((pInst->flag & FLAG_ACTIVE) == 0) || (pInst->pObject->type != TYPE_ASTEROID)) continue; AEVec2Sub(&u, &pInst->posCurr, &spShip->posCurr); if (AEVec2Length(&u) < (spShip->scale * 10.0f)) { sparkCreate (PTCL_EXPLOSION_M, &pInst->posCurr, 10, -PI, PI); gameObjInstDestroy(pInst); } } // reduce the ship counter sShipCtr--; // if counter is less than 0, game over if (sShipCtr < 0) { sGameStateChangeCtr = 2.0; gameObjInstDestroy(spShip); spShip = 0; } break; } } } #endif // ===================================== // calculate the matrix for all objects // ===================================== for (u32 i = 0; i < GAME_OBJ_INST_NUM_MAX; i++) { GameObjInst* pInst = sGameObjInstList + i; AEMtx33 m; // skip non-active object if ((pInst->flag & FLAG_ACTIVE) == 0) continue; AEMtx33Scale (&pInst->transform, pInst->scale, pInst->scale); AEMtx33Rot (&m, pInst->dirCurr); AEMtx33Concat (&pInst->transform, &m, &pInst->transform); AEMtx33Trans (&m, pInst->posCurr.x, pInst->posCurr.y); AEMtx33Concat (&pInst->transform, &m, &pInst->transform); } }
/** * Steps the world. * * This function is not complete, may need some rework. */ void DYN_stepWorld(DYN_Context *context) { int i, j; double remainingTime = 1; double nearestPoints[6]; int stuckCtr = 0; if (simStopped) return; while (remainingTime > 0) { char wasCollision = 0; // STEP 1: Moving bodies for (i = 0; i < context->bodyCount; i++) { moveBody(&context->bodies[i], remainingTime); } // STEP 2: Collision detection for (i = 0; i < context->bodyCount; i++) { context->bodies[i].colliding = 0; context->bodies[i].inContact = 0; } for (i = 0; i < context->bodyCount; i++) { for (j = i + 1; j < context->bodyCount; j++) { double nearestPoints[6]; int tmp[2]; tmp[0] = i; tmp[1] = j; if (AVL_find(&context->ncPairIndex, tmp)) { continue; } if (COL_collide(&context->bodies[i], &context->bodies[j], nearestPoints, 0)) { addCollidingPair(context, i, j); wasCollision = 1; } } } if (wasCollision) { double currentImpulseVector[3]; double currentCollisionPoint[3]; double minTime = 1; int earlyAIndex = -1, earlyBIndex = -1; // There was collision // STEP 3: Find earliest collision int i; int cpCount = DYNA_getLength(&context->collidingPairs); int (*collidingPairs)[2] = DYNA_getStorage(&context->collidingPairs); // Find the earliest collision. assert(cpCount); for (i = 0; i < cpCount; i++) { DYN_Body *a = &context->bodies[collidingPairs[i][0]]; DYN_Body *b = &context->bodies[collidingPairs[i][1]]; double lower = 0; double upper = remainingTime; int stuckCtr2 = 0; char nearestSet = 0; for(;;stuckCtr2++) { double middle = (lower + upper) * 0.5; revertMovement(a); revertMovement(b); moveBody(a, middle); moveBody(b, middle); if (COL_collide(a, b, nearestPoints, 0)) { upper = middle; } else { nearestSet = 1; lower = middle; } assert(lower != upper); if (nearestSet) { double tmp[3]; ALG_getPointToPointVector(tmp, nearestPoints, &nearestPoints[3]); if ((ALG_dotProduct(tmp, tmp) < 1e-6) || (fabs(upper-lower) < 1e-6)) { // The two bodies are near each other. if (middle <= minTime) { minTime = middle; earlyAIndex = collidingPairs[i][0]; earlyBIndex = collidingPairs[i][1]; memcpy(currentImpulseVector, tmp, sizeof(currentImpulseVector)); memcpy(currentCollisionPoint, nearestPoints, sizeof(currentCollisionPoint)); } break; } } } } { DYN_Body *a = &context->bodies[earlyAIndex]; DYN_Body *b = &context->bodies[earlyBIndex]; fprintf(DYN_log, "Collision!\n"); fprintf(DYN_log, "Body index A: %d\n", earlyAIndex); fprintf(DYN_log, "Body index B: %d\n", earlyBIndex); fprintf(DYN_log, "Velocity A [%g, %g, %g] %g\n", a->velocity[0], a->velocity[1], a->velocity[2], ALG_getVectorLength(a->velocity)); fprintf(DYN_log, "Velocity B [%g, %g, %g] %g\n", b->velocity[0], b->velocity[1], b->velocity[2], ALG_getVectorLength(b->velocity)); fprintf(DYN_log, "Collision point [%g, %g, %g]\n", currentCollisionPoint[0], currentCollisionPoint[1], currentCollisionPoint[2]); fprintf( DYN_log, "Impulse vector [%g, %g, %g] %g\n", currentImpulseVector[0], currentImpulseVector[1], currentImpulseVector[2], ALG_getVectorLength(currentImpulseVector) ); fprintf(DYN_log, "Elapsed time: %g\n", context->elapsedTime + context->timeStep * (1 - remainingTime)); } // Revert and move all bodies to the collision moment. for (i = 0; i < context->bodyCount; i++) { DYN_Body *current = &context->bodies[i]; revertMovement(current); moveBody(current, minTime); } assert(earlyAIndex >= 0); assert(earlyBIndex >= 0); // Resolve the collision { CollisionResult result = resolveCollision( context, &context->bodies[earlyAIndex], &context->bodies[earlyBIndex], currentCollisionPoint, currentImpulseVector ); if (result == DYN_STICKEDTOGETHER) { addNonCollidingPair(context, earlyAIndex, earlyBIndex); context->bodies[earlyAIndex].inContact = 1; context->bodies[earlyBIndex].inContact = 1; } } memcpy(DYN_lastCollisionPoint, currentCollisionPoint, sizeof(DYN_lastCollisionPoint)); memcpy(DYN_lastImpulse, currentImpulseVector, sizeof(DYN_lastImpulse)); fprintf(DYN_log, "==============================\n"); // clearCollidingPairs(context); // Continue the simulation remainingTime -= minTime; } else { // No collision, step finished break; } stuckCtr++; if (stuckCtr >= 100) { simStopped = 1; return; } } // STEP 4: repelling non-colliding pairs { int i; int n = DYNA_getLength(&context->nonCollidingPairs); int (*ncPairs)[2] = (int (*)[2])DYNA_getStorage(&context->nonCollidingPairs); double lastSimplex[12]; for (i = 0; i < n; i++) { DYN_Body *a = &context->bodies[ncPairs[i][0]]; DYN_Body *b = &context->bodies[ncPairs[i][1]]; if (COL_collide(a, b, 0, lastSimplex)) { double penetrationVector[3]; fprintf(DYN_log, "Sticked and colliding after timestep!\n"); COL_getPenetrationVector(a, b, lastSimplex, penetrationVector); fprintf( DYN_log, "Penetration vector was: [%g, %g, %g]\n", penetrationVector[0], penetrationVector[1], penetrationVector[2] ); { // push it out from the body and a little. double penetrationVectorLength = ALG_getVectorLength(penetrationVector); double scaleFactor = (penetrationVectorLength + 0.01) / penetrationVectorLength; ALG_scale(penetrationVector, scaleFactor); } ALG_translate(b->position, penetrationVector); fprintf(DYN_log, "==============================\n"); a->colliding = a->inContact = 0; b->colliding = a->inContact = 0; { // Body b may collide with other bodies. Translate those bodies as well. DYNA_Array tmp; int j; DYNA_initialize(&tmp, sizeof(DYN_Body*)); DYNA_add(&tmp, b); for (j = 0; j < DYNA_getLength(&tmp); j++) { DYN_Body **storage = DYNA_getStorage(&tmp); DYN_Body *current = storage[j]; int k = 0; for (k = 0; k < context->bodyCount; k++) { DYN_Body *other = &context->bodies[k]; if (other == current) continue; if (COL_collide(current, other, 0, 0)) { ALG_translate(other->position, penetrationVector); current->colliding = 0; other->colliding = 0; DYNA_add(&tmp, other); } } } DYNA_deinitialize(&tmp); } } } } clearNonCollidingPairs(context); context->elapsedTime += context->timeStep; }