void Garden::setTerrain(TerrainTile &terrain) { terrain.reset(); terrain.setOverlay(this); terrain.setBuilding(true); terrain.setGarden(true); }
void Garden::setTerrain(TerrainTile &terrain) { terrain.reset(); terrain.setOverlay(this); terrain.setBuilding(true); // are gardens buildings or not???? try to investigate from original game terrain.setGarden(true); }
void Plaza::setTerrain(TerrainTile &terrain) { //std::cout << "Plaza::setTerrain" << std::endl; terrain.reset(); terrain.setOverlay(this); terrain.setRoad(true); }
uint8 TerrainHolder::GetLiquidType(float x, float y) { TerrainTile* tile = GetTile(x, y); if (tile == NULL) return 0; uint8 rv = tile->m_map.GetLiquidType(x, y); tile->DecRef(); return rv; }
float TerrainHolder::GetLiquidHeight(float x, float y) { TerrainTile* tile = GetTile(x, y); if (tile == NULL) return TERRAIN_INVALID_HEIGHT; float rv = tile->m_map.GetLiquidHeight(x, y); tile->DecRef(); return rv; }
void Terrain::traverse(osg::NodeVisitor &nv) { if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { // need to check if any TerrainTechniques need to have their update called on them. osgUtil::UpdateVisitor *uv = dynamic_cast<osgUtil::UpdateVisitor*>(&nv); if (uv) { typedef std::list<osg::ref_ptr<TerrainTile> > TerrainTileList; TerrainTileList tiles; { OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex); for (TerrainTileSet::iterator itr = _updateTerrainTileSet.begin(); itr != _updateTerrainTileSet.end(); ++itr) { // take a reference first to make sure that the referenceCount can be safely read without another thread decrementing it to zero. (*itr)->ref(); // only if referenceCount is 2 or more indicating there is still a reference held elsewhere is it safe to add it to list of tiles to be updated if ((*itr)->referenceCount() > 1) tiles.push_back(*itr); // use unref_nodelete to avoid any issues when the *itr TerrainTile has been deleted by another thread while this for loop has been running. (*itr)->unref_nodelete(); } _updateTerrainTileSet.clear(); } for (TerrainTileList::iterator itr = tiles.begin(); itr != tiles.end(); ++itr) { TerrainTile *tile = itr->get(); tile->traverse(nv); } } } if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { osgUtil::CullVisitor *cv = dynamic_cast<osgUtil::CullVisitor*>(&nv); osg::StateSet *ss = _geometryPool.valid() ? _geometryPool->getRootStateSetForTerrain(this) : 0; if (cv && ss) { cv->pushStateSet(ss); Group::traverse(nv); cv->popStateSet(); return; } } Group::traverse(nv); }
TerrainTile* TerrainHolder::GetTile(int32 tx, int32 ty) { TerrainTile* rv = NULL; m_lock[tx][ty].Acquire(); rv = m_tiles[tx][ty]; if (rv != NULL) rv->AddRef(); m_lock[tx][ty].Release(); return rv; }
void Building::setTerrain(TerrainTile &terrain) { // here goes the problem // when we reset tile, we delete information // about it's original information // try to fix bool isMeadow = terrain.isMeadow(); terrain.reset(); terrain.setOverlay(this); terrain.setBuilding(true); terrain.setMeadow(isMeadow); }
uint32 TerrainHolder::GetAreaFlag(float x, float y) { TerrainTile* tile = GetTile(x, y); if (tile == NULL) { // No generated map for this area (usually instances) return 0; } uint32 rv = tile->m_map.GetArea(x, y); tile->DecRef(); return rv; }
void drawWater(float maxX,float maxY,float minX,float minY){ TerrainTile water; water.red = 0; water.green = 0; water.blue = .1; water.alpha = .8; water.z1 = 0; water.z2 = 0; water.z3 = 0; water.z4 = 0; water.x=minX; water.y=minY; water.xMax =maxX; water.yMax =maxY; water.drawTile(); }
void TerrainMap::UpdateInfoLayer(int LayerChangeIndex) { TerrainTile *Temp = NULL; for (int x = 0; x < m_MapSizeX; x++) { for (int y = 0; y < m_MapSizeY; y++) { Temp = &m_Map[LayerChangeIndex]->Get_Tile(Vec2i(x, y)); if (Temp->Get_Collidable()) { m_InfoLayer[x][y] = Temp; } } } }
TerrainTile::TerrainTile(const TerrainTile& terrain,const osg::CopyOp& copyop): Group(terrain,copyop), _terrain(0), _dirtyMask(NOT_DIRTY), _hasBeenTraversal(false), _elevationLayer(terrain._elevationLayer), _colorLayers(terrain._colorLayers), _requiresNormals(terrain._requiresNormals), _treatBoundariesToValidDataAsDefaultValue(terrain._treatBoundariesToValidDataAsDefaultValue), _blendingPolicy(terrain._blendingPolicy) { if (terrain.getTerrainTechnique()) { setTerrainTechnique(dynamic_cast<TerrainTechnique*>(terrain.getTerrainTechnique()->clone(osg::CopyOp::SHALLOW_COPY))); } }
TerrainTile Level::convert_byte(int y, int x, unsigned char byte){ float sheet_width = 914.0f; float sheet_height = 936.0f; TerrainTile tile; //tile.exists = false; if (byte == (unsigned char)1){ //"stoneCenter.png" x="144" y="576" width="70" height="70" Sheetposition position = Sheetposition(144.0f, 576.0f, 70.0f, 70.0f, tilesize, sheet_width, sheet_height); tile = TerrainTile(x*tilesize + tilesize/2, y*tilesize +tilesize/2, tile_texture, position, program); tile.set_behaviors(true, true, true, true); tile.set_exists(true); tile.set_hitbox(tilesize, tilesize); } else if (byte == (unsigned char)2){ //"stoneMid.png" x="72" y="432" width="70" height="70" Sheetposition position = Sheetposition(72.0f, 432.0f, 70.0f, 70.0f, tilesize, sheet_width, sheet_height); tile = TerrainTile(x * tilesize + tilesize /2, y*tilesize + tilesize /2, tile_texture, position, program); tile.set_behaviors(true, true , true, true); tile.set_exists(true); tile.set_hitbox(tilesize, tilesize); } return tile; }
//Returns true if can be placed at this position bool World::canBePlacedAtPixelPos(sf::Vector2i _pos){ //If out of bounds, return false immediately if (_pos.x >= getDimensionsInPixels().x || _pos.y >= getDimensionsInPixels().y || _pos.x <= 0 || _pos.y <= 0){ return false; } TerrainTile* here = terrainLayer[indexAtPixelPos(_pos)].get(); if (here->getUnit() == nullptr){ return true; } else{ return false; } }
bool World::canBePlacedAtCartesianPos(sf::Vector2i _pos){ //If out of bounds, return false immediately if (_pos.x > getDimensions().x - 1 || _pos.y > getDimensions().y - 1 || _pos.x < 0 || _pos.y < 0){ return false; } TerrainTile* here = terrainLayer[indexAtCartesianPos(_pos)].get(); if (here->getUnit() == nullptr){ return true; } else{ return false; } }
void TerrainMap::InitInfoLayer() { m_InfoLayer.resize(m_MapSizeX, std::vector<TerrainTile*>(m_MapSizeY, NULL)); TerrainTile *Temp = NULL; for (int i = 0; i < m_Map.size(); i++) { for (int x = 0; x < m_MapSizeX; x++) { for (int y = 0; y < m_MapSizeY; y++) { Temp = &m_Map[i]->Get_Tile(Vec2i(x, y)); if (Temp->Get_Collidable()) { m_InfoLayer[x][y] = Temp; } } } } }
void Terrain::traverse(osg::NodeVisitor& nv) { if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR) { // need to check if any TerrainTechniques need to have their update called on them. osgUtil::UpdateVisitor* uv = dynamic_cast<osgUtil::UpdateVisitor*>(&nv); if (uv) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); for(TerrainTileSet::iterator itr = _updateTerrainTileSet.begin(); itr != _updateTerrainTileSet.end(); ++itr) { TerrainTile* tile = *itr; tile->traverse(nv); } _updateTerrainTileSet.clear(); } } Group::traverse(nv); }
TerrainTile * ctb::TerrainTiler::createTile(const TileCoordinate &coord) const { // Get a terrain tile represented by the tile coordinate TerrainTile *terrainTile = new TerrainTile(coord); GDALTile *rasterTile = createRasterTile(coord); // the raster associated with this tile coordinate GDALRasterBand *heightsBand = rasterTile->dataset->GetRasterBand(1); // Copy the raster data into an array float rasterHeights[TerrainTile::TILE_CELL_SIZE]; if (heightsBand->RasterIO(GF_Read, 0, 0, TILE_SIZE, TILE_SIZE, (void *) rasterHeights, TILE_SIZE, TILE_SIZE, GDT_Float32, 0, 0) != CE_None) { throw CTBException("Could not read heights from raster"); } delete rasterTile; // Convert the raster data into the terrain tile heights. This assumes the // input raster data represents meters above sea level. Each terrain height // value is the number of 1/5 meter units above -1000 meters. // TODO: try doing this using a VRT derived band: // (http://www.gdal.org/gdal_vrttut.html) for (unsigned short int i = 0; i < TerrainTile::TILE_CELL_SIZE; i++) { terrainTile->mHeights[i] = (i_terrain_height) ((rasterHeights[i] + 1000) * 5); } // If we are not at the maximum zoom level we need to set child flags on the // tile where child tiles overlap the dataset bounds. if (coord.zoom != maxZoomLevel()) { CRSBounds tileBounds = mGrid.tileBounds(coord); if (! (bounds().overlaps(tileBounds))) { terrainTile->setAllChildren(false); } else { if (bounds().overlaps(tileBounds.getSW())) { terrainTile->setChildSW(); } if (bounds().overlaps(tileBounds.getNW())) { terrainTile->setChildNW(); } if (bounds().overlaps(tileBounds.getNE())) { terrainTile->setChildNE(); } if (bounds().overlaps(tileBounds.getSE())) { terrainTile->setChildSE(); } } } return terrainTile; }
bool World::calculateViewDistance(UnitTile* unit, TerrainTile* target, bool randomisePerceivedPositions){ //IMPORTANT: //Due to the fact that Tile::getCartesianPos() bases its result on the physical location of the sprite, //which for units can be in disagreement with its real position, we use getTruePosition() instead. bool enemyFound{false}; sf::Vector2i currentPos = target->getCartesianPos(); int unitViewDistance = unit->getDefaultUnitViewDistance() - getWeatherUnitViewDistance(); int flagViewDistance = unit->getDefaultFlagViewDistance() - getWeatherFlagViewDistance(); if(getIsNighttime()){ unitViewDistance /= 2; flagViewDistance /= 2; } if(unitViewDistance < 1){ unitViewDistance = 1; } if(flagViewDistance < 1){ flagViewDistance = 1; } unit->setCurrentUnitViewDistance(unitViewDistance); unit->setCurrentFlagViewDistance(flagViewDistance); Player* owner = unit->getPlayer(); for (int y{-1 * unitViewDistance}; y <= unitViewDistance; ++y){ for(int x{-1 * unitViewDistance}; x <= unitViewDistance; ++x){ sf::Vector2i adjacentPos{currentPos.x + x, currentPos.y + y}; TerrainTile* terrainHere = terrainAtCartesianPos(adjacentPos); if(terrainHere == nullptr){ continue; } UnitTile* targetUnit = terrainHere->getUnit(); visibleTiles.insert(terrainHere); if (targetUnit != nullptr){ if(targetUnit->getPlayer() != owner){ if(!targetUnit->drawUnit){ enemyFound = true; targetUnit->drawUnit = true; } targetUnit->updateStats(randomisePerceivedPositions); } } } } for (int y{-1 * flagViewDistance}; y <= flagViewDistance; ++y){ for(int x{-1 * flagViewDistance}; x <= flagViewDistance; ++x){ sf::Vector2i adjacentPos{currentPos.x + x, currentPos.y + y}; TerrainTile* terrainHere = terrainAtCartesianPos(adjacentPos); if(terrainHere == nullptr){ continue; } UnitTile* targetUnit = terrainHere->getUnit(); if (targetUnit != nullptr){ if(targetUnit->getPlayer() != owner){ targetUnit->drawFlag = true; targetUnit->updateStats(randomisePerceivedPositions); } } } } return enemyFound; }
PLAYER_UPDATE_STATE Player::Update(float delta_, Goal* goal_, std::vector<Bullet> bullets_, std::set<TerrainTile*> monitoredTiles_) { playerWaitTimer += delta_; animationTimer += delta_; //set animation if (animationTimer > 0.6f) { animationTimer = 0.0f; animSwitch++; if (animSwitch % 2 == 0) { playerTexture = textures[0]; } else { playerTexture = textures[1]; } } if (spotted && behaviour != FLEE) { cout << "behaviour == FLEE" << endl; behaviour = FLEE; navigationList.clear(); spotted = false; } //update player on normal path //while the navigationList is not empty. if (navigationList.empty() && behaviour == SEEK) { // //convert click location to tile TerrainTile* dstTile = terrain->TileAtMouseCoords(goal_->Pos()); //convert player location to tile TerrainTile* playerTile = terrain->TileAtMouseCoords(static_cast<int>(pos.x), static_cast<int>(pos.y)); // //get the vector of tiles to nav to navigationList = terrain->ShortestPath(playerTile, dstTile, monitoredTiles_); } if (navigationList.empty() && behaviour == FLEE) { TerrainTile* playerTile = terrain->TileAtMouseCoords(static_cast<int>(pos.x), static_cast<int>(pos.y)); //get a new path from terrain to get away from enemy navigationList = terrain->ClosestUnmonitoredTile(playerTile, monitoredTiles_); //is current tile monitored? if (std::find(monitoredTiles_.begin(), monitoredTiles_.end(), playerTile) == monitoredTiles_.end()) { behaviour = SEEK; } } ////wait for x seconds //if (navigationList.empty() && behaviour == FLEE) //{ // cout << "behaviour == WAIT" << endl; // behaviour = WAIT; //} //if (behaviour == WAIT) //{ // // if (playerWaitTimer > 0.1f) // { // playerWaitTimer = 0.0f; // cout << "behaviour == SEEK" << endl; // behaviour = SEEK; // } //} if (!navigationList.empty()) { //if ( behaviour != WAIT ) //{ //get the next node and move towards it TerrainTile* nextNode = navigationList[navigationList.size() - 1]; Vector2 nextNodePos = nextNode->Pos(); //if reached pop it off the top if ((pos - nextNode->Pos()).GetMagnitude() < 1.0f) { pos = nextNode->Pos(); navigationList.erase(navigationList.end() - 1); navigationList.clear(); } else { int currentTerrainCost = 1; if ((pos - nextNode->Pos()).GetMagnitude() < TILE_SIZE * 0.5f) { currentTerrainCost = nextNode->Cost(); } //TODO FIX - .GetNormal does not work on vector with Magnitude of 0 Vector2 direction = (nextNodePos - pos).GetNormal(); Vector2 velocity = (direction * 75) * delta_; velocity *= 1.f / (float)currentTerrainCost; pos += velocity; //rotate animation if (direction.x > 0.6) //heading right { RotateSprite(playerTexture, 0); } else if (direction.x < -0.6) //heading left { RotateSprite(playerTexture, PI); } else if (direction.y > 0.6) //heading down { RotateSprite(playerTexture, PI / 2); } else if (direction.y < -0.6) //heading up { RotateSprite(playerTexture, -(PI / 2)); } } //if ( playerWaitTimer > 2.0f ) //{ // navigationList.clear(); // playerWaitTimer = 0.0f; //} //} } //update player rect rect.centre = pos; //check if bullet collided with player for (auto& bullet : bullets_) { if (Collision::RectCollision(bullet.GetRect(), rect)) { cout << "bullet struck player" << endl; return PUS_DIED; } } if (terrain->TileAtMouseCoords(pos) == terrain->TileAtMouseCoords(goal_->Pos())) { return PUS_WON; } // if (IsKeyDown(SDLK_UP) || IsKeyDown(SDLK_w)) // { // pos.y -= 100 * delta_; // } // if (IsKeyDown(SDLK_DOWN) || IsKeyDown(SDLK_s)) // { // pos.y += 100 * delta_; // } // if (IsKeyDown(SDLK_RIGHT) || IsKeyDown(SDLK_d)) // { // pos.x += 100 * delta_; // } // if (IsKeyDown(SDLK_LEFT) || IsKeyDown(SDLK_a)) // { // pos.x -= 100 * delta_; // } return PUS_NORMAL; }
void TerrainGenerator::diamondSquare(TerrainTile & tile) const { // assuming the edge length of the field is a power of 2, + 1 // assuming the field is square const unsigned fieldEdgeLength = tile.samplesPerAxis; const float maxHeight = m_settings.maxHeight; float randomMax = 50.0f; std::function<float(float)> clampHeight = [maxHeight](float value) { if (value > maxHeight) value = maxHeight; if (value < -maxHeight) value = -maxHeight; return value; }; std::function<void(unsigned int, unsigned int, unsigned int, std::function<float(unsigned int, unsigned int)>&)> squareStep = [&tile, fieldEdgeLength, &clampHeight](unsigned int diamondRadius, unsigned int diamondCenterRow, unsigned int diamondCenterColumn, std::function<float(unsigned int, unsigned int)>& heightRnd) { // get the existing data values first: if we get out of the valid range, wrap around, to the next existing value on the other field side int upperRow = signed(diamondCenterRow) - signed(diamondRadius); if (upperRow < 0) upperRow = fieldEdgeLength - 1 - diamondRadius; // example: nbRows=5, centerRow=0, upperRow gets -1, we want the second last row (with existing value), so it's 3 int lowerRow = signed(diamondCenterRow) + signed(diamondRadius); if (lowerRow >= signed(fieldEdgeLength)) lowerRow = diamondRadius; // this is easier: use the first row in our column, that is already set int leftColumn = signed(diamondCenterColumn) - signed(diamondRadius); if (leftColumn < 0) leftColumn = fieldEdgeLength - 1 - diamondRadius; int rightColumn = signed(diamondCenterColumn) + signed(diamondRadius); if (rightColumn >= signed(fieldEdgeLength)) rightColumn = diamondRadius; float value = (tile.valueAt(upperRow, diamondCenterColumn) + tile.valueAt(lowerRow, diamondCenterColumn) + tile.valueAt(diamondCenterRow, leftColumn) + tile.valueAt(diamondCenterRow, rightColumn)) * 0.25f + heightRnd(diamondCenterRow, diamondCenterColumn); float clampedHeight = clampHeight(value); tile.setValue(diamondCenterRow, diamondCenterColumn, clampedHeight); // in case we are at the borders of the tile: also set the value at the opposite border, to allow seamless tile wrapping if (upperRow > signed(diamondCenterRow)) tile.setValue(fieldEdgeLength - 1, diamondCenterColumn, clampedHeight); if (leftColumn > signed(diamondCenterColumn)) tile.setValue(diamondCenterRow, fieldEdgeLength - 1, clampedHeight); }; unsigned nbSquareRows = 1; // number of squares in a row, doubles each time the current edge length increases [same for the columns] for (unsigned int len = fieldEdgeLength; len > 2; len = (len / 2) + 1) // length: 9, 5, 3, finished { const unsigned int currentEdgeLength = len; std::uniform_real_distribution<float> dist(-randomMax, randomMax); std::function<float(unsigned int, unsigned int)> heightRndPos = [fieldEdgeLength, &dist](unsigned int row, unsigned int column) { glm::vec2 pos(row, column); pos = pos / (fieldEdgeLength - 1.0f) * 2.0f - 1.0f; return float(glm::length(pos)) * dist(rng); //return std::abs(float(row + column) / float(2 * fieldEdgeLength - 2) * 2.0f - 1.0f) * dist(rng); }; // create diamonds for (unsigned int rowN = 0; rowN < nbSquareRows; ++rowN) { const unsigned int row = rowN * (currentEdgeLength - 1); const unsigned int midpointRow = row + (currentEdgeLength - 1) / 2; // this is always divisible, because of the edge length 2^n + 1 for (unsigned int columnN = 0; columnN < nbSquareRows; ++columnN) { const unsigned int column = columnN * (currentEdgeLength - 1); const unsigned int midpointColumn = column + (currentEdgeLength - 1) / 2; float heightValue = (tile.valueAt(row, column) + tile.valueAt(row + currentEdgeLength - 1, column) + tile.valueAt(row, column + currentEdgeLength - 1) + tile.valueAt(row + currentEdgeLength - 1, column + currentEdgeLength - 1)) * 0.25f + heightRndPos(midpointRow, midpointColumn); tile.setValue(midpointRow, midpointColumn, clampHeight(heightValue)); } } // create squares unsigned int diamondRadius = (currentEdgeLength - 1) / 2; // don't iterate over the last row/column here. These values are set with the first row/column, to allow seamless tile wrapping for (unsigned int rowN = 0; rowN < nbSquareRows; ++rowN) { const unsigned int seedpointRow = rowN * (currentEdgeLength - 1); for (unsigned int columnN = 0; columnN < nbSquareRows; ++columnN) { const unsigned int seedpointColumn = columnN * (currentEdgeLength - 1); unsigned int rightDiamondColumn = seedpointColumn + currentEdgeLength / 2; if (rightDiamondColumn < tile.samplesPerAxis) squareStep(diamondRadius, seedpointRow, rightDiamondColumn, heightRndPos); unsigned int bottomDiamondRow = seedpointRow + currentEdgeLength / 2; if (bottomDiamondRow < tile.samplesPerAxis) squareStep(diamondRadius, bottomDiamondRow, seedpointColumn, heightRndPos); } } nbSquareRows *= 2; randomMax *= 0.5; } }
float TerrainInteraction::setValue(TerrainTile & tile, unsigned row, unsigned column, float value, bool setToInteractionElement) { float stddev = tile.interactStdDeviation; assert(stddev > 0); /** clamp value */ if (value < tile.minValidValue) value = tile.minValidValue; if (value > tile.maxValidValue) value = tile.maxValidValue; // define the size of the affected interaction area, in grid coords const float effectRadiusWorld = stddev * 3; const uint32_t effectRadius = static_cast<uint32_t>(std::ceil(effectRadiusWorld * tile.samplesPerWorldCoord)); // = 0 means to change only the value at (row,column) bool moveUp = (value - tile.valueAt(row, column)) > 0; int invert = moveUp ? 1 : -1; // invert the curve if moving downwards float norm0Inv = 1.0f / normalDist(0, 0, stddev); float valueRange = std::abs(tile.maxValidValue - tile.minValidValue); std::function<float(float)> interactHeight = [stddev, norm0Inv, value, valueRange, invert](float x) { return normalDist(x, 0, stddev) // - normalize normDist to * norm0Inv // normDist value at interaction center * (valueRange + 10) // - scale to value range + offset to omit norm values near 0 * invert // - mirror the curve along the y axis if moving downward + value // - move along y so that value==0 => y==0 - (valueRange + 10) * invert; }; unsigned int minRow, maxRow, minColumn, maxColumn; { // unchecked signed min/max values, possibly < 0 or > numRows/Column int iMinRow = row - effectRadius, iMaxRow = row + effectRadius, iMinColumn = column - effectRadius, iMaxColumn = column + effectRadius; // work on rows and column that are in range of the terrain tile settings and larger than 0 minRow = iMinRow < 0 ? 0 : (iMinRow >= static_cast<signed>(tile.samplesPerAxis) ? tile.samplesPerAxis - 1 : static_cast<unsigned int>(iMinRow)); maxRow = iMaxRow < 0 ? 0 : (iMaxRow >= static_cast<signed>(tile.samplesPerAxis) ? tile.samplesPerAxis - 1 : static_cast<unsigned int>(iMaxRow)); minColumn = iMinColumn < 0 ? 0 : (iMinColumn >= static_cast<signed>(tile.samplesPerAxis) ? tile.samplesPerAxis - 1 : static_cast<unsigned int>(iMinColumn)); maxColumn = iMaxColumn < 0 ? 0 : (iMaxColumn >= static_cast<signed>(tile.samplesPerAxis) ? tile.samplesPerAxis - 1 : static_cast<unsigned int>(iMaxColumn)); } // also change element id's if requested and the tile supports it PhysicalTile * physicalTile = dynamic_cast<PhysicalTile*>(&tile); if (setToInteractionElement) { assert(physicalTile); } uint8_t elementIndex = 0; if (physicalTile) elementIndex = physicalTile->elementIndex(m_interactElement); for (unsigned int r = minRow; r <= maxRow; ++r) { float relWorldX = (signed(r) - signed(row)) * tile.sampleInterval; for (unsigned int c = minColumn; c <= maxColumn; ++c) { float relWorldZ = (signed(c) - signed(column)) * tile.sampleInterval; float localRadius = std::sqrt(relWorldX*relWorldX + relWorldZ*relWorldZ); if (localRadius > effectRadiusWorld) // interaction in a circle, not square continue; float newLocalHeight = interactHeight(localRadius); bool localMoveUp = newLocalHeight > tile.valueAt(r, c); // don't do anything if we pull up the terrain but the local height point is already higher than its calculated height. (vice versa) if (localMoveUp != moveUp) continue; tile.setValue(r, c, newLocalHeight); if (setToInteractionElement) physicalTile->setElement(r, c, elementIndex); } tile.addBufferUpdateRange(minColumn + r * tile.samplesPerAxis, 1u + effectRadius * 2u); } if (physicalTile) physicalTile->addToPxUpdateBox(minRow, maxRow, minColumn, maxColumn); return value; }
void Terrain::buildGeometry(Ogre::SceneNode* parent, bool editable) { clearGeometry(); assert(parent); // NB: We must adjust world geometry bounding box, especially for OctreeSceneManager Ogre::AxisAlignedBox aabb = mData->getBoundBox(); Ogre::Vector3 centre = aabb.getCenter(); const Ogre::Vector3 adjust(2000, 10000, 2000); const Ogre::Real scale = 1.5f; aabb.setExtents( (aabb.getMinimum() - centre) * scale + centre - adjust, (aabb.getMaximum() - centre) * scale + centre + adjust); parent->getCreator()->setOption("Size", &aabb); mEditable = editable; if (!mData->mXSize || !mData->mZSize) { // Do nothing if it's empty terrain. return; } // Prepare atlas texture for (size_t pixmapId = 0, numPixmap = mData->mPixmaps.size(); pixmapId < numPixmap; ++pixmapId) { _getPixmapAtlasId(pixmapId); } prepareLightmapTexture(); int depth = mData->mZSize; int width = mData->mXSize; int tileSize = mData->mTileSize; int numTilePerX = mData->mNumTilePerX; int numTilePerZ = mData->mNumTilePerZ; if (mEditable) { mGridTypeInfos.resize(2); mGridTypeInfos[0].material.setNull(); mGridTypeInfos[1].material = Ogre::MaterialManager::getSingleton().getByName( "FairyEditor/GridType"); } else { _initIndexBuffer(tileSize * tileSize); } mTiles.reserve(numTilePerX * numTilePerZ); for (int z = 0; z < numTilePerZ; ++z) { for (int x = 0; x < numTilePerX; ++x) { // Create the tile int tileX = x * tileSize; int tileZ = z * tileSize; int tileWidth = std::min(width - tileX, tileSize); int tileDepth = std::min(depth - tileZ, tileSize); TerrainTile* tile; if (mEditable) tile = new TerrainTileEditable(parent, this, tileX, tileZ, tileWidth, tileDepth); else tile = new TerrainTileOptimized(parent, this, tileX, tileZ, tileWidth, tileDepth); // Use the render queue that the world geometry associated with. tile->setRenderQueueGroup(parent->getCreator()->getWorldGeometryRenderQueue()); // Attach it to the aux data mTiles.push_back(tile); } } }
void Aqueduct::setTerrain(TerrainTile &terrain) { terrain.reset(); terrain.setOverlay(this); terrain.setBuilding(true); }
void Road::setTerrain(TerrainTile &terrain) { terrain.reset(); terrain.setOverlay(this); terrain.setRoad(true); }
void setTerrain( TerrainTile& terrain ) { terrain.clearFlags(); terrain.setOverlay( this ); terrain.setRoad( true ); }
void World::turnlyUpdate(){ boost::random::uniform_int_distribution<int> dist(1, 100); incrementElapsedTurns(); getCurrentTime().increment(); //The weather will tend to change every ~8 hours, or 480 minutes. //Ideally, something like this: //1 hour (60) -> 4% //2 hours (120) -> 6% //3 hours (180) -> 8% //4 hours (240) -> 12.5% //5 hours (300) -> 16% //6 hours (360) -> 24% //7 hours (420) -> 30% //8 hours (480) -> 40% for(auto& effect : weatherEffects){ effect.second += minutesPerTurn; } auto effect = std::begin(weatherEffects); while(effect != std::end(weatherEffects)){ int removeEffect{dist(masterManager.randomEngine)}; //For instance, if the effect has been there for 240 minutes, it will have an //40% chance of being removed. There is a hard cap of 80%. int totalChance = effect->second / 15; if(totalChance > 50){ totalChance = 50; } if(removeEffect <= totalChance){ effect = weatherEffects.erase(effect); } else{ effect++; } } int hourlyChance = 20; int turnlyChance = hourlyChance / (60/minutesPerTurn); int randomRoll{dist(masterManager.randomEngine)}; if (randomRoll <= turnlyChance){ addWeather(); } //////////////////////////////////////////////////////////////////////////////// //////////////////MUD CREATION AND REMOVAL////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //Firstly, depending on whether the rain is heavy or light, there will be a varying //amount of mud formations per turn. bool rain{false}; int minimumMudFormations{0}; for(auto& effect : weatherEffects){ if(effect.first == World::Weather::HEAVY_RAIN){ rain = true; minimumMudFormations = 4; break; } else if(effect.first == World::Weather::LIGHT_RAIN){ rain = true; minimumMudFormations = 2; break; } } //A random tile on the map that we call the origin is converted to mud (if possible). if(rain){ for (int i{0}; i < minimumMudFormations; ++i){ boost::random::uniform_int_distribution<int> randomIndexDist(0, getDimensions().x * getDimensions().y); int randomIndex{randomIndexDist(masterManager.randomEngine)}; sf::Vector2i originPosition{cartesianPosAtIndex(randomIndex)}; TerrainTile* origin = terrainAtCartesianPos(originPosition); bool originConvertedToMud{false}; if(origin->getTerrainType() == TerrainTile::TerrainType::MEADOW){ toggleMud(origin); originConvertedToMud = true; } if(!originConvertedToMud){ break; } //There is then an 4/5 chance that a neighboring tile is also converted, if possible... int randomNumber{0}; do{ boost::random::uniform_int_distribution<int> randomDist(1, 5); randomNumber = randomDist(masterManager.randomEngine); if(randomNumber >= 2){ boost::random::uniform_int_distribution<int> randomDisplacementDist(-1, 1); int randomDisplacementX{randomDisplacementDist(masterManager.randomEngine)}; int randomDisplacementY{randomDisplacementDist(masterManager.randomEngine)}; sf::Vector2i newPosition{originPosition.x + randomDisplacementX, originPosition.y + randomDisplacementY}; TerrainTile* newTerrain = terrainAtCartesianPos(newPosition); if(newTerrain != nullptr){ if(newTerrain->getTerrainType() == TerrainTile::TerrainType::MEADOW){ toggleMud(newTerrain); } } } //... and a 3/5 chance for this process to repeat. }while(randomNumber >= 3); } //While new mud tiles are formed, every old mud tile has a 1/8 chance to spread to a neighboring tile, if possible //IMPORTANT NOTE: here we use an integer-based index rather than a foreach loop, because toggleMud() //itself actually erases a mud tile from mudTiles. So if we do a foreach mudTiles loop, we end up with //messy dangling pointers and, in my case, days of debugging crashes. for(std::vector<Mud*>::size_type i{0}; i < mudTiles.size(); i++){ boost::random::uniform_int_distribution<int> randomDist(1, 8); int randomNumber = randomDist(masterManager.randomEngine); if(randomNumber == 1){ boost::random::uniform_int_distribution<int> randomDisplacementDist(-1, 1); int randomDisplacementX{randomDisplacementDist(masterManager.randomEngine)}; int randomDisplacementY{randomDisplacementDist(masterManager.randomEngine)}; sf::Vector2i originPosition = mudTiles[i]->getCartesianPos(); sf::Vector2i newPosition{originPosition.x + randomDisplacementX, originPosition.y + randomDisplacementY}; TerrainTile* newTerrain = terrainAtCartesianPos(newPosition); if(newTerrain != nullptr){ if(newTerrain->getTerrainType() == TerrainTile::TerrainType::MEADOW){ toggleMud(newTerrain); } } } } } //Finally, after the rain has stopped, each mud tile has a 9/10 chance to dry up. else if (!rain){ //IMPORTANT NOTE: here we use an integer-based index rather than a foreach loop, because toggleMud() //itself actually erases a mud tile from mudTiles. So if we do a foreach mudTiles loop, we end up with //messy dangling pointers and, in my case, days of debugging crashes. for(std::vector<Mud*>::size_type i{0}; i < mudTiles.size(); i++){ boost::random::uniform_int_distribution<int> randomDryingChanceDist(1, 10); int randomDryingChance{randomDryingChanceDist(masterManager.randomEngine)}; if(randomDryingChance <= 9){ toggleMud(mudTiles[i]); } } } unhighlightVisibleTiles(); visibleTiles.clear(); }
void Reservoir::setTerrain(TerrainTile &terrain) { terrain.reset(); terrain.setOverlay(this); terrain.setBuilding(true); }
void GameState_Setup::getInput(){ sf::Event event; while (game->mWindow.pollEvent(event)){ switch (event.type){ case sf::Event::MouseMoved: game->mousePos.x = event.mouseMove.x; game->mousePos.y = event.mouseMove.y; break; case sf::Event::Resized: handleResize(); break; case sf::Event::MouseButtonPressed: if (event.mouseButton.button == sf::Mouse::Middle){ middleButtonHeld = true; middleButtonCoords = {event.mouseButton.x, event.mouseButton.y}; } else if (event.mouseButton.button == sf::Mouse::Left && drawUI){ //If no menu item was selectedSpawnableUnit, select it if (selectedSpawnableUnit == nullptr){ sf::Vector2f worldCoords{game->mWindow.mapPixelToCoords(game->mousePos, *game->currentView)}; sf::Vector2f uiCoords{game->mWindow.mapPixelToCoords(game->mousePos, setupUI.uiView)}; std::vector<SpawnableUnit> current{game->currentPlayer->getSpawnableUnits()}; for (size_t i{0}; i < current.size(); ++i){ if (uiCoords.x > current[i].left() && uiCoords.x < current[i].right() && uiCoords.y > current[i].top() && uiCoords.y < current[i].bottom()){ selectedSpawnableUnit = std::move(std::unique_ptr<SpawnableUnit>(new SpawnableUnit(current[i]))); break; } } if (uiCoords.x >= setupUI.getButton().left() && uiCoords.x <= setupUI.getButton().right() && uiCoords.y >= setupUI.getButton().top() && uiCoords.y <= setupUI.getButton().bottom()){ //As long as the player has at least one non-general unit if (game->currentPlayer->getDeploymentPoints() <= game->currentPlayer->getMaxDeploymentPoints() - 1){ game->currentPlayer->setReady(true); } } if(selectedSpawnableUnit == nullptr){ middleButtonHeld = true; middleButtonCoords = {event.mouseButton.x, event.mouseButton.y}; } } //Spawn a unit on the tile: else{ sf::Vector2i mouseCoords{event.mouseButton.x, event.mouseButton.y}; sf::Vector2i worldCoords{game->mWindow.mapPixelToCoords(mouseCoords, *game->currentView)}; TerrainTile* terrain = game->mWorld->terrainAtPixelPos(worldCoords); if (terrain != nullptr){ if(terrain->getTerrainType() != TerrainTile::TerrainType::WATER){ game->currentPlayer->spawnUnit(selectedSpawnableUnit->unitID, worldCoords); } } selectedSpawnableUnit = nullptr; break; } } else if (event.mouseButton.button == sf::Mouse::Right && drawUI){ //Deselect the currently selectedSpawnableUnit icon: if (selectedSpawnableUnit != nullptr){ selectedSpawnableUnit = nullptr; break; } //Delete a unit from a tile: else{ sf::Vector2i mouseCoords{event.mouseButton.x, event.mouseButton.y}; sf::Vector2i worldCoords{game->mWindow.mapPixelToCoords(mouseCoords, *game->currentView)}; auto removed = game->currentPlayer->removeUnit(worldCoords); if(removed != nullptr){ game->currentPlayer->setDeploymentPoints(game->currentPlayer->getDeploymentPoints() + removed.get()->getCost()); } break; } } break; case sf::Event::MouseButtonReleased: if (event.mouseButton.button == sf::Mouse::Middle){ middleButtonHeld = false; } else if(event.mouseButton.button == sf::Mouse::Left){ middleButtonHeld = false; } break; case sf::Event::Closed: game->exitGame(false); break; case sf::Event::KeyPressed: switch (event.key.code){ case Key::UP_KEY: cameraVelocity = {0.f, -2.f}; break; case Key::RIGHT_KEY: cameraVelocity = {2.f, 0.f}; break; case Key::DOWN_KEY: cameraVelocity = {0.f, 2.f}; break; case Key::LEFT_KEY: cameraVelocity = {-2.f, 0.f}; break; case Key::RESETZOOM_KEY: game->currentView->setSize(game->mWindow.getSize().x, game->mWindow.getSize().y); break; case Key::ZOOMIN_KEY: game->currentView->setSize(game->currentView->getSize().x - xResolution / 10, game->currentView->getSize().y - yResolution / 10); break; case Key::ZOOMOUT_KEY: game->currentView->setSize(game->currentView->getSize().x + xResolution / 10, game->currentView->getSize().y + yResolution / 10); break; case sf::Keyboard::Escape: { game->setGameState(game->SetupPauseMenuState.get()); } break; case Key::HIDE_UI_KEY: if (drawUI){ drawUI = false; } else if (!drawUI){ drawUI = true; } break; default: break; } break; case sf::Event::MouseWheelMoved: smoothZoom_zooming = true; smoothZoom_lerpFactor = 0.0085f; if (event.mouseWheel.delta > 0 && game->currentView->getSize().x > xResolution && game->currentView->getSize().y > yResolution){ //zoom in //std::cout << game->currentView->getSize().x << ',' << game->currentView->getSize().y << std::endl; //game->currentView->setSize(game->currentView->getSize().x - xResolution / 12, game->currentView->getSize().y - yResolution / 12); smoothZoom_targetZoom = 0.8f; } else if (event.mouseWheel.delta < 0 && game->currentView->getSize().x < xResolution * 4 && game->currentView->getSize().y < yResolution * 4){ //zoom out //std::cout << game->currentView->getSize().x << ',' << game->currentView->getSize().y << std::endl; //game->currentView->setSize(game->currentView->getSize().x + xResolution / 12, game->currentView->getSize().y + yResolution / 12); smoothZoom_targetZoom = 1.2f; } smoothZoom_currentZoom = 1.0f; smoothZoom_previousZoom = smoothZoom_currentZoom; smoothZoom_currentCenter = game->currentView->getCenter(); if(smoothZoom_targetZoom >= 1.f){ smoothZoom_targetCenter = game->mWindow.mapPixelToCoords(game->mousePos, *(game->currentView)); auto dist = smoothZoom_targetCenter - smoothZoom_currentCenter; dist.x /= 2; dist.y /= 2; smoothZoom_targetCenter = smoothZoom_currentCenter - dist; } else{ smoothZoom_targetCenter = game->mWindow.mapPixelToCoords(game->mousePos, *(game->currentView)); auto dist = smoothZoom_targetCenter - smoothZoom_currentCenter; dist.x /= 2; dist.y /= 2; smoothZoom_targetCenter = smoothZoom_targetCenter - dist; } break; default: break; } } }