void Chunk::PlaceTileAt(int x,int y, int type) { GetTileAt(x, y)->type = type; for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { Tile* tilePtr = GetTileAt(i, j); CheckSurroundings(tilePtr); } } }
// See if the tile located at a position is a door and also needs // to be oriented in a certain way // If there are walls or doors in the neighbourhood, they can force a certain // orientation of the door static int HasDoorOrientedAt(Mission *m, Vec2i pos,int isHorizontal) { unsigned short tile = GetTileAt(m, pos); if (tile != MAP_DOOR) { return 0; } // Check for walls and doors that force the orientation of the door if (GetTileAt(m, Vec2iNew(pos.x - 1, pos.y)) == MAP_WALL || GetTileAt(m, Vec2iNew(pos.x - 1, pos.y)) == MAP_DOOR || GetTileAt(m, Vec2iNew(pos.x + 1, pos.y)) == MAP_WALL || GetTileAt(m, Vec2iNew(pos.x + 1, pos.y)) == MAP_DOOR) { // There is a horizontal door return isHorizontal; } else if (GetTileAt(m, Vec2iNew(pos.x, pos.y - 1)) == MAP_WALL || GetTileAt(m, Vec2iNew(pos.x, pos.y - 1)) == MAP_DOOR || GetTileAt(m, Vec2iNew(pos.x, pos.y + 1)) == MAP_WALL || GetTileAt(m, Vec2iNew(pos.x, pos.y + 1)) == MAP_DOOR) { // There is a vertical door return !isHorizontal; } // There is a door but it is free to be oriented in any way return 0; }
vector<Entity*> GameView::GetEntitiesInRadius(const Vector2& in_pos, float in_radius) { vector<Entity*> res; Tile* tile = GetTileAt(in_pos); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } // get all the tiles around it tile = GetTileAt(in_pos + Vector2(-1,0)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(-1, -1)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(0, -1)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(1, -1)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(1, 0)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(1, 1)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(0, 1)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } tile = GetTileAt(in_pos + Vector2(-1, 1)); if (tile) { FillVectorWithEntitiesInRadius(tile, in_pos, in_radius, res); } return res; }
bool MissionTrySetTile(Mission *m, Vec2i pos, unsigned short tile) { if (pos.x < 0 || pos.x >= m->Size.x || pos.y < 0 || pos.y >= m->Size.y) { return false; } CASSERT(m->Type == MAPTYPE_STATIC, "cannot set tile for map type"); switch (tile) { case MAP_WALL: // Check that there are no incompatible doors if (HasDoorOrientedAt(m, Vec2iNew(pos.x - 1, pos.y), 0) || HasDoorOrientedAt(m, Vec2iNew(pos.x + 1, pos.y), 0) || HasDoorOrientedAt(m, Vec2iNew(pos.x, pos.y - 1), 1) || HasDoorOrientedAt(m, Vec2iNew(pos.x, pos.y + 1), 1)) { // Can't place this wall return false; } break; case MAP_DOOR: { // Check that there is a clear passage through this door int isHClear = IsClear(GetTileAt(m, Vec2iNew(pos.x - 1, pos.y))) && IsClear(GetTileAt(m, Vec2iNew(pos.x + 1, pos.y))); int isVClear = IsClear(GetTileAt(m, Vec2iNew(pos.x, pos.y - 1))) && IsClear(GetTileAt(m, Vec2iNew(pos.x, pos.y + 1))); if (!isHClear && !isVClear) { return false; } // Check that there are no incompatible doors if (HasDoorOrientedAt(m, Vec2iNew(pos.x - 1, pos.y), 0) || HasDoorOrientedAt(m, Vec2iNew(pos.x + 1, pos.y), 0) || HasDoorOrientedAt(m, Vec2iNew(pos.x, pos.y - 1), 1) || HasDoorOrientedAt(m, Vec2iNew(pos.x, pos.y + 1), 1)) { // Can't place this door return false; } } break; } const int idx = pos.y * m->Size.x + pos.x; *(unsigned short *)CArrayGet(&m->u.Static.Tiles, idx) = tile; return true; }
void GameView::SpawnMonster() { if (Monster::count >= MAX_MONSTER_COUNT) return; for (int tries = 0; tries < 10; ++tries) { int side = onut::randi() % 4; Vector2 spawnPos; switch (side) { case 0: spawnPos = onut::rand2f(Vector2::Zero, Vector2((float)m_pTilemap->getWidth(), 2.5f)); break; case 1: spawnPos = onut::rand2f(Vector2::Zero, Vector2(2.5f, (float)m_pTilemap->getHeight())); break; case 2: spawnPos = onut::rand2f(Vector2((float)m_pTilemap->getWidth() - 2.5f, 0.f), Vector2(Vector2((float)m_pTilemap->getWidth(), (float)m_pTilemap->getHeight()))); break; case 3: spawnPos = onut::rand2f(Vector2(0.f, (float)m_pTilemap->getHeight() - 2.5f), Vector2(Vector2((float)m_pTilemap->getWidth(), (float)m_pTilemap->getHeight()))); break; } spawnPos.x = std::round(spawnPos.x) + .5f; spawnPos.y = std::round(spawnPos.y) + .5f; auto pTile = GetTileAt(spawnPos); if (!pTile) continue; if (!pTile->isOccupied) { auto pMonster = new Monster(MonsterType::CRAWLER, this, spawnPos); AddEntity(pMonster); break; } } }
void Chunk::DigTileAt(int x,int y) { RemoveTileAt(x, y); for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { Tile* tilePtr = GetTileAt(i, j); CheckSurroundings(tilePtr); } } }
void GameView::OnEntityMoved(Entity* pEntity) { m_pGameLayer->Detach(pEntity); m_pGameLayer->Attach(pEntity, (int)(pEntity->GetPosition().y * 16.f)); auto pTile = GetTileAt(pEntity->GetPosition()); if (pTile) { pTile->RegisterEntity(pEntity); } }
void GameView::GenerateMap() { Vector2 mapCenter((float)m_pTilemap->getWidth() * .5f, (float)m_pTilemap->getHeight() * .5f); m_pStockpile = new Stockpile(this, m_pTilemap->getWidth() / 2 + 1, m_pTilemap->getHeight() / 2 - 4); AddEntity(m_pStockpile); // Spawn a bunch of trees for (int i = 0; i < TREE_DENSITY; ++i) { auto center = onut::rand2f(Vector2::Zero, Vector2((float)m_pTilemap->getWidth(), (float)m_pTilemap->getHeight())); int count = onut::randi(2, 12); for (int j = 0; j < count; ++j) { auto pos = center += onut::rand2f(Vector2(-3), Vector2(3)); pos.x = std::round(pos.x) + .5f; pos.y = std::round(pos.y) + .5f; if (pos.x >= mapCenter.x - 3 && pos.y >= mapCenter.y - 3 && pos.x <= mapCenter.x + 3 && pos.y <= mapCenter.y + 3) continue; if (pos.x < 1.f || pos.y < 1.f || pos.x >(float)m_pTilemap->getWidth() - 1.f || pos.y >(float)m_pTilemap->getHeight() - 1.f) continue; auto pTile = GetTileAt(pos); if (!pTile) continue; if (pTile->isOccupied) continue; pTile->isOccupied = true; auto pTree = new Tree(this, pos); AddEntity(pTree); } } // Spawn a bunch of rockz for (int i = 0; i < ROCK_DENSITY; ++i) { auto center = onut::rand2f(Vector2::Zero, Vector2((float)m_pTilemap->getWidth(), (float)m_pTilemap->getHeight())); int count = onut::randi(2, 6); for (int j = 0; j < count; ++j) { auto pos = center += onut::rand2f(Vector2(-3), Vector2(3)); pos.x = std::round(pos.x) + .5f; pos.y = std::round(pos.y) + .5f; if (pos.x >= mapCenter.x - 3 && pos.y >= mapCenter.y - 3 && pos.x <= mapCenter.x + 3 && pos.y <= mapCenter.y + 3) continue; if (pos.x < 1.f || pos.y < 1.f || pos.x >(float)m_pTilemap->getWidth() - 1.f || pos.y >(float)m_pTilemap->getHeight() - 1.f) continue; auto pTile = GetTileAt(pos); if (!pTile) continue; if (pTile->isOccupied) continue; pTile->isOccupied = true; auto pRock = new Rock(this, pos); AddEntity(pRock); } } for (int i = 0; i < m_pTilemap->getWidth(); ++i) { GetTileAt(i, 0)->isOccupied = true; GetTileAt(0, i)->isOccupied = true; GetTileAt(i, m_pTilemap->getHeight() - 1)->isOccupied = true; GetTileAt(m_pTilemap->getWidth() - 1, i)->isOccupied = true; } }
int Chunk::GetItemFromTile(int x,int y) { switch (GetTileAt(x,y)->type) { case Type::DIRT: case Type::GRASS: return 2; break; case Type::COBBLE: return 3; break; default: return 0; } }
void GameView::ClearEntities() { for (size_t i = 0; i < m_entitiesToKill.size(); ++i) { for (auto it = m_scarecrows.begin(); it != m_scarecrows.end();) { if ((*it) == m_entitiesToKill[i]) { it = m_scarecrows.erase(it); break; } else { ++it; } } for (auto it = m_entities.begin(); it != m_entities.end();) { if ((*it) == m_entitiesToKill[i]) { it = m_entities.erase(it); DeleteNode(m_entitiesToKill[i]); break; } else { ++it; } } } m_entitiesToKill.clear(); for (auto pEntity : m_entitiesToAdd) { m_pGameLayer->Attach(pEntity, (int)(pEntity->GetPosition().y * 16.f)); m_entities.push_back(pEntity); auto pTile = GetTileAt(pEntity->GetPosition()); if (pTile) { pTile->RegisterEntity(pEntity); } if (dynamic_cast<Scarecrow*>(pEntity)) { m_scarecrows.push_back(pEntity); } } m_entitiesToAdd.clear(); }
void Chunk::CheckSurroundings(Tile* currentTilePtr) { if (currentTilePtr == nullptr) return; bool left, right, top, bottom; left = CheckTileToAir(currentTilePtr,GetTileAt(currentTilePtr->x - 1, currentTilePtr->y)); right = CheckTileToAir(currentTilePtr,GetTileAt(currentTilePtr->x + 1, currentTilePtr->y)); top = CheckTileToAir(currentTilePtr,GetTileAt(currentTilePtr->x, currentTilePtr->y - 1)); bottom = CheckTileToAir(currentTilePtr,GetTileAt(currentTilePtr->x, currentTilePtr->y + 1)); currentTilePtr->air = BoolToInt(left, right, top, bottom); left = CheckTileToBackgroundAir(currentTilePtr, GetTileAt(currentTilePtr->x - 1, currentTilePtr->y)); right = CheckTileToBackgroundAir(currentTilePtr, GetTileAt(currentTilePtr->x + 1, currentTilePtr->y)); top = CheckTileToBackgroundAir(currentTilePtr, GetTileAt(currentTilePtr->x, currentTilePtr->y - 1)); bottom = CheckTileToBackgroundAir(currentTilePtr, GetTileAt(currentTilePtr->x, currentTilePtr->y + 1)); currentTilePtr->noBackround = BoolToInt(left, right, top, bottom); }
void TileSetPanel::OnLeftButtonPressed(wxMouseEvent& event) { if (!m_tileset || m_tileset->IsDirty()) return; wxPoint mousePos = CalcUnscrolledPosition(event.GetPosition()); //Select the tile int selectedCol, selectedRow; GetTileAt(mousePos, selectedCol, selectedRow); if (selectedCol >= m_tileset->GetColumnsCount() || selectedRow >= m_tileset->GetRowsCount()) return; m_selectedCol = selectedCol; m_selectedRow = selectedRow; //Send the event TileSelectionEvent newEvent(TILE_SELECTION_CHANGED, GetId(), m_tileset->GetTileIDFromCell(m_selectedCol, m_selectedRow)); newEvent.SetEventObject(this); ProcessWindowEvent(newEvent); Refresh(); }
// Utility: returns true is the tile is walkable bool j1PathFinding::IsWalkable(const iPoint& pos) const { uchar t = GetTileAt(pos); return t != INVALID_WALK_CODE && t > 0; }
void TileMapPanel::OnMouseEvent(wxMouseEvent &event) { if(!m_tilemap || !m_tileset) return; //Get the current tile position (column and row) int currentColumn, currentRow; wxPoint mousePos = CalcUnscrolledPosition(event.GetPosition()); GetTileAt(mousePos, currentColumn, currentRow); if(currentColumn >= m_tilemap->GetColumnsCount() || currentRow >= m_tilemap->GetRowsCount()) return; //Stop if the position is out of range if(m_insertionMode == PencilMode) { if(event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_RIGHT_DOWN || event.GetEventType() == wxEVT_MOTION) { if(event.LeftIsDown()) //Left mouse button pressed { //Add a tile to the current position (only if the tile has not been set before) if(m_tilemap->GetTile(m_mapCurrentLayer, currentColumn, currentRow) != m_tileToBeInserted) m_commandProcessor.Submit(new ChangeTileCommand(*m_tilemap, m_mapCurrentLayer, currentColumn, currentRow, m_tileToBeInserted)); Refresh(); } else if(event.RightIsDown()) { //Remove the tile if(m_tilemap->GetTile(m_mapCurrentLayer, currentColumn, currentRow) != m_tileToBeInserted) m_commandProcessor.Submit(new ChangeTileCommand(*m_tilemap, m_mapCurrentLayer, currentColumn, currentRow, -1)); Refresh(); } } } else if(m_insertionMode == RectangleMode) { if(event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_RIGHT_DOWN) { m_isDrawingRectangle = true; m_beginCol = m_endCol = currentColumn; m_beginRow = m_endRow = currentRow; Update(); } else if(event.GetEventType() == wxEVT_MOTION) { m_endCol = currentColumn; m_endRow = currentRow; Update(); } else if(event.GetEventType() == wxEVT_LEFT_UP) { m_endCol = currentColumn; m_endRow = currentRow; m_isDrawingRectangle = false; m_commandProcessor.Submit(new ChangeTileCommand(*m_tilemap, m_mapCurrentLayer, std::min(m_beginCol, m_endCol), std::min(m_beginRow, m_endRow), std::max(m_beginCol, m_endCol), std::max(m_beginRow, m_endRow), m_tileToBeInserted)); Update(); } else if(event.GetEventType() == wxEVT_RIGHT_UP) { m_endCol = currentColumn; m_endRow = currentRow; m_isDrawingRectangle = false; m_commandProcessor.Submit(new ChangeTileCommand(*m_tilemap, m_mapCurrentLayer, std::min(m_beginCol, m_endCol), std::min(m_beginRow, m_endRow), std::max(m_beginCol, m_endCol), std::max(m_beginRow, m_endRow), -1)); Update(); } } else if(m_insertionMode == FillMode) { if(event.GetEventType() == wxEVT_LEFT_DOWN) { m_commandProcessor.Submit(new FloodFillCommand(*m_tilemap, m_mapCurrentLayer, currentColumn, currentRow, m_tileToBeInserted)); Update(); } } }
Tile *GameView::GetTileAt(const Vector2& position) const { auto x = (int)position.x; auto y = (int)position.y; return GetTileAt(x, y); }