AsteroidFieldChunkServer::AsteroidFieldChunkServer(int asteroidNumber, float chunkSideLength, float astMinSize, float astMaxSize, uint32_t ownerId, osg::Vec3i chunk, GameInstanceServer* ctx, PhysicsEngine* engine) : GameObject(ownerId, ctx) { m_chunkCoord = chunk; m_physicsEngine = engine; std::random_device randDevice; //Generate Asteroid Field //step 1: scatter asteroids. save to AsteroidField m_asteroids = std::make_shared<AsteroidField>(); float astSizeDif = astMaxSize - astMinSize; float asteroidCubeMaxSidelength = astMaxSize * 2; float radius; osg::Vec3f pos; for (int i = 0; i < asteroidNumber; i++) { pos.set( randDevice()*1.0f / randDevice.max() * chunkSideLength, randDevice()*1.0f / randDevice.max() * chunkSideLength, randDevice()*1.0f / randDevice.max() * chunkSideLength); radius = ( ( randDevice() * 1.0f / randDevice.max() ) * ( randDevice() * 1.0f / randDevice.max() ) * astSizeDif + astMinSize ) * 0.5f; m_asteroids->addAsteroid(pos, radius); } //step 2: move asteroids to avoid overlappings (heuristic). save to Level::asteroidField int accuracy = 10; //how often d'you wanna apply heuristic? for (int iterations = 0; iterations < accuracy; iterations++) { std::shared_ptr<AsteroidField> previousScattering = m_asteroids; m_asteroids = std::make_shared<AsteroidField>(); for (int i = 0; i < asteroidNumber; i++) { float favoredDistance = (asteroidCubeMaxSidelength - astMaxSize) / 2 + previousScattering->getAsteroid(i)->getRadius(); float boundingBoxRadius = favoredDistance + astMaxSize / 2; std::list<Asteroid*> candidates = previousScattering->getAsteroidsInBlock(previousScattering->getAsteroid(i)->getPosition(), osg::Vec3f(boundingBoxRadius, boundingBoxRadius, boundingBoxRadius)); osg::Vec3f shift(0, 0, 0); int numberOfCloseAsteroids = 0; for (std::list<Asteroid*>::iterator it = candidates.begin(); it != candidates.end(); it++) { if (*it != previousScattering->getAsteroid(i)) { osg::Vec3f d = previousScattering->getAsteroid(i)->getPosition() - (*it)->getPosition(); float scale = -((d.length() - (*it)->getRadius()) - favoredDistance); if (scale > 0) { d.normalize(); shift += shift + (d * scale *0.5f); //push away from other close asteroids numberOfCloseAsteroids++; } } } m_asteroids->addAsteroid(previousScattering->getAsteroid(i)->getPosition() + shift, previousScattering->getAsteroid(i)->getRadius()); } } // Add asteroids as collision bodies to the engine for (unsigned int i = 0; i < m_asteroids->getLength(); ++i) { Asteroid* currentAst = m_asteroids->getAsteroid(i); unsigned int id = engine->addCollisionSphere(currentAst->getPosition() + GameInstanceServer::chunkToPosition(m_chunkCoord), currentAst->getRadius()); m_physicsIds.push_back(id); } }
bool LaserPhysicsComponent::testIntersectionWithAsteroid(Laser &laser, Asteroid &asteroid) { D3DXVECTOR3 currLaserPos = laser.getPosition(), lastLaserPos = laser.getLastPosition(), laserDir = laser.getDirection(), asteroidPosition = asteroid.getPosition(); float asteroidRadius = getAsteroidBoundingSphereRadius(asteroid); float asteroidPosToLaserEnd; //check if the laser ray intersects a rough bounding sphere of the asteroid if (!D3DXSphereBoundProbe(&asteroidPosition, asteroidRadius, &lastLaserPos, &laserDir)) { return false; } asteroidPosToLaserEnd = D3DXVec3LengthSq(&(currLaserPos - asteroidPosition)); //if this is true then the laser's current position does not fall within the sphere, and a ray starting at the laser's //current point crosses the circle. A ray starting at the last point already crosses the sphere, so this means both //points are "before" the sphere, along the ray in the direction the laser is travelling. if (asteroidRadius * asteroidRadius < asteroidPosToLaserEnd && D3DXSphereBoundProbe(&asteroidPosition, asteroidRadius, &currLaserPos, &laserDir)) { return false; } //it may have collided. Now check ray against mesh shared_ptr<GraphicsComponent> gfx = asteroid.getGraphicsComponent(); AsteroidGraphicsComponent *asteroidGraphicsComponent = dynamic_cast<AsteroidGraphicsComponent*>(gfx.get()); if (asteroidGraphicsComponent == NULL) { throw "Asteroid didn't have a valid asteroid graphics component!"; } BOOL hit; float dist; D3DXVECTOR3 laserPosRelativeToAsteroid = lastLaserPos - asteroidPosition; D3DXVECTOR3 asteroidScale = asteroid.getScale(); D3DXQUATERNION rotationQuat = asteroid.getRotationQuat(); D3DXMATRIX rot, scale; D3DXMatrixScaling(&scale, 0.8f/asteroidScale.x, 0.8f/asteroidScale.y, 0.8f/asteroidScale.z); D3DXMatrixRotationQuaternion(&rot, &rotationQuat); D3DXVec3TransformCoord(&laserPosRelativeToAsteroid, &laserPosRelativeToAsteroid, &(scale * rot)); D3DXIntersect(asteroidGraphicsComponent->getMesh(), &laserPosRelativeToAsteroid, &laserDir, &hit, NULL, NULL, NULL, &dist, NULL, NULL); float distTravelledSq = D3DXVec3LengthSq(&(currLaserPos - lastLaserPos)); if (!hit || dist * dist > D3DXVec3LengthSq(&(currLaserPos - lastLaserPos))) { return false; } return true; }