예제 #1
0
void OrganismCellWorld::calculateVortex()
{
    for (auto vortexIter = vortices.begin(); vortexIter != vortices.end();)
    {
        sf::Vector2i pos = (*vortexIter).getPos();

        // Is the tile occupied alive
        if (cells[indexFromPos(pos.x, pos.y)].alive)
        {
            // Do we still have time left
            if ((*vortexIter).ticksLeft > 0)
            {
                --(*vortexIter).ticksLeft;
                toRemove += suck;
            }
            // Remove
            else
            {
                // "Advance" vortexIter
                vortexIter = vortices.erase(vortexIter);
                continue;
            }
        }

        // Advance vortexIter
        ++vortexIter;
    }
}
예제 #2
0
void OrganismCellWorld::updateDeathChances()
{
    for (auto& cell : cells)
    {
        cell.deathChance = 0.f;
    }

    const int cursorEffectSize = 10;
    const float strength = 20.f;
    const float maxChance = .30f; // This should be < 1-(cell die chance)

    // Increase likelihood of cells being killed near cursor
    for (int x = static_cast<int>(negCursor.x) - cursorEffectSize; x < static_cast<int>(negCursor.x) + cursorEffectSize; ++x)
    {
        for (int y = static_cast<int>(negCursor.y) - cursorEffectSize; y < static_cast<int>(negCursor.y) + cursorEffectSize; ++y)
        {
            size_t index = indexFromPos(x, y);
            float dx1 = ECSE::wrapDifference(negCursor.x, static_cast<float>(x), static_cast<float>(width)),
                dy1 = ECSE::wrapDifference(negCursor.y, static_cast<float>(y), static_cast<float>(height));
            float dist = sqrt(dx1 * dx1 + dy1 * dy1);

            if (dist == 0.f) cells[index].deathChance = maxChance;
            else  {
                cells[index].deathChance = ECSE::clamp(0.f, maxChance, strength / (dist * dist * dist));
            }
        }
    }
}
예제 #3
0
void OrganismCellWorld::calculateFood()
{
    for (auto foodIter = food.begin(); foodIter != food.end(); )
    {
        sf::Vector2i pos = (*foodIter).getPos();

        auto& cell = cells[indexFromPos(pos.x, pos.y)];

        // Is the tile occupied alive and part of the player
        if (cell.alive && cell.attached)
        {
            // Do we still have time left
            if ((*foodIter).ticksLeft > 0)
            {
                --(*foodIter).ticksLeft;
                toAdd += feed;
            }
            // Remove
            else
            {
                // "Advance" foodIter
                foodIter = food.erase(foodIter);
                ++score;
                continue;
            }
        }

        // Advance foodIter
        ++foodIter;
    }
}
예제 #4
0
void OrganismCellWorld::moveCursor()
{
    // Get input
    float dxPos = engine->inputManager.getFloatValue(0),
        dyPos = engine->inputManager.getFloatValue(1),
        dxNeg = engine->inputManager.getFloatValue(2),
        dyNeg = engine->inputManager.getFloatValue(3);

    // 5 = width and height of cursor sprite
    int indexPos = indexFromPos(static_cast<int>(posCursor.x + dxPos * 5.f), static_cast<int>(posCursor.y + dyPos * 5.f)),
        indexNeg = indexFromPos(static_cast<int>(negCursor.x + dxPos * 5.f), static_cast<int>(negCursor.y + dyPos * 5.f));

    auto movementPos = sf::Vector2f(dxPos, dyPos),
        movementNeg = sf::Vector2f(dxNeg, dyNeg);
    ECSE::normalize(movementPos);
    ECSE::normalize(movementNeg);

    // Move at full speed inside the cell
    if (aliveCount >= 200)
    {
        if (cells[indexPos].alive)
        {
            posCursor += movementPos * 1.5f;
        }
        // Slower outside of the cell
        else
        {
            posCursor += movementPos * 0.25f;
        }
    }

    // Move slower inside the cell
    if (cells[indexNeg].alive) {
        negCursor += movementNeg * 0.25f;
    }
    // Faster outside of the cell
    else {
        negCursor += movementNeg * 1.5f;
    }

    // Mod to wrap
    posCursor.x = static_cast<float>(fmod(posCursor.x + width, width));
    posCursor.y = static_cast<float>(fmod(posCursor.y + height, height));
    negCursor.x = static_cast<float>(fmod(negCursor.x + width, width));
    negCursor.y = static_cast<float>(fmod(negCursor.y + height, height));
}
예제 #5
0
void OrganismCellWorld::init()
{
    CellWorld<OrganismCell>::init();

    // Set defaults for modifiers
    modifiers.push_back(DIE_CHANCE_DEF);
    modifiers.push_back(DIE_NEIGH_DEF);
    modifiers.push_back(ALIVE_NEIGH_DEF);

    // Give reference to modifiers
    for (auto& cell : cells) {
        cell.mods = &modifiers;
    }

    sf::Vector2i center
    {
        static_cast<int>(width / 2),
        static_cast<int>(height / 2)
    };

    for (unsigned int x = 0; x < width; ++x)
    {
        for (unsigned int y = 0; y < height; ++y)
        {
            auto cell = &cells[indexFromPos(x, y)];

            int dx = x - center.x;
            int dy = y - center.y;

            cell->alive = sqrt(dx * dx + dy * dy) < width * 0.15;
        }
    }

    posCursor.x = static_cast<float>(center.x);
    posCursor.y = static_cast<float>(center.y);
    negCursor.x = static_cast<float>(center.x + 50);
    negCursor.y = static_cast<float>(center.y);

    indexOrganisms();
}
예제 #6
0
void OrganismCellWorld::redistributeCells()
{
    size_t indexPosCur = indexFromPos(static_cast<int>(posCursor.x), static_cast<int>(posCursor.y));
    if (cells[indexPosCur].organism != 0)
    {
        playerOrganism = cells[indexPosCur].organism;
    }

    for (auto& cell : cells)
    {
        cell.attached = cell.organism == playerOrganism;
    }

    std::map<unsigned, std::vector<size_t>> born;
    std::map<unsigned, std::vector<size_t>> died;
    std::vector<size_t> changed;
    std::set<unsigned> organisms;

    for (size_t i = 0; i < cells.size(); ++i)
    {
        auto& cell = cells[i];

        if (cell.nextAlive && !cell.alive)
        {
            born[cell.organism].push_back(i);
            organisms.insert(cell.organism);
        }
        else if (!cell.nextAlive && cell.alive)
        {
            died[cell.organism].push_back(i);
            organisms.insert(cell.organism);
        }
    }

    // DEBUG ADD/REMOVE FOOD
    if (engine->inputManager.getIntValue(4) > 0) toAdd += 100;
    else if (engine->inputManager.getIntValue(4) < 0) toRemove += 100;

    // Accumulate number of dead cells
    toRemove += decay;

    for (auto organism : organisms)
    {
        auto& orgBorn = born[organism];
        auto& orgDied = died[organism];

        // Shuffle the list of cells that died/were born
        std::random_shuffle(orgBorn.begin(), orgBorn.end());
        std::random_shuffle(orgDied.begin(), orgDied.end());

        auto bornIter = orgBorn.begin();
        auto diedIter = orgDied.begin();

        if (organism == playerOrganism)
        {
            // If we've accumulated enough decay, kill off some cells permanently
            while (toRemove > 1.f && diedIter != orgDied.end())
            {
                cells[*diedIter].alive = false;
                changed.push_back(*diedIter);
                ++diedIter;

                toRemove -= 1.f;
            }

            // If we have cells to add then do so
            while (toAdd > 0 && bornIter != orgBorn.end())
            {
                cells[*bornIter].alive = true;
                changed.push_back(*bornIter);
                ++bornIter;

                toAdd -= 1;
            }
        }
        else
        {
            // Kill cells randomly
            unsigned killRandom = rand() % 8;
            for (unsigned i = 0; i < killRandom && diedIter != orgDied.end(); ++i)
            {
                cells[*diedIter].alive = false;
                changed.push_back(*diedIter);
                ++diedIter;
            }
        }

        // Redistribute dead cells into born cells
        while (bornIter != orgBorn.end() && diedIter != orgDied.end())
        {
            cells[*bornIter].alive = true;
            cells[*diedIter].alive = false;

            changed.push_back(*bornIter);
            changed.push_back(*diedIter);

            ++bornIter;
            ++diedIter;
        }
    }

    std::random_shuffle(changed.begin(), changed.end());

    for (auto& index : changed)
    {
        cells[index].organism = 0;

        for (auto neighbor : getNeighborIndices(index))
        {
            cells[neighbor].organism = 0;
        }
    }

    for (auto it = changed.begin(); it != changed.end(); ++it)
    {
        auto index = *it;
        auto& cell = cells[index];

        // Newly-created; find nearby organisms
        if (cell.alive)
        {
            if (cell.organism == 0) floodFillOrganism(index, true);
        }
        // Newly-destroyed; neighbors may have split into new organisms
        else
        {
            for (auto neighborIndex : getNeighborIndices(index))
            {
                auto& neighbor = cells[neighborIndex];

                if (neighbor.alive && neighbor.organism == 0) floodFillOrganism(neighborIndex, false);
            }
        }
    }

    aliveCount = 0;
    for (auto& cell : cells)
    {
        if (cell.alive && cell.attached) ++aliveCount;
    }
}
예제 #7
0
void OrganismCellWorld::updateBirthChances()
{
    for (auto& cell : cells)
    {
        cell.birthChance = 0.f;
    }

    // Below a certain number of cells, disable player control and let the death spiral finish
    if (aliveCount < 200) return;

    const int cursorEffectSize = 10;
    const float strength = 10.f;

    // Increase likelihood of cells being born near cursor
    for (int x = static_cast<int>(posCursor.x) - cursorEffectSize; x < static_cast<int>(posCursor.x) + cursorEffectSize; ++x)
    {
        for (int y = static_cast<int>(posCursor.y) - cursorEffectSize; y < static_cast<int>(posCursor.y) + cursorEffectSize; ++y)
        {
            size_t index = indexFromPos(x, y);
            float dx1 = ECSE::wrapDifference(posCursor.x, static_cast<float>(x), static_cast<float>(width)),
                  dy1 = ECSE::wrapDifference(posCursor.y, static_cast<float>(y), static_cast<float>(height));
            float dist = sqrt(dx1 * dx1 + dy1 * dy1);
            
            if (dist == 0.f) cells[index].birthChance = 1.f;
            else cells[index].birthChance = ECSE::clamp(0.f, 1.f, strength / (dist * dist));
        }
    }

    const int foodEffectSize = 15;
    const float foodStrength = 25.f;
    // Increase likelihood of cells being born near food
    for (auto& foodObj : food) {
        sf::Vector2i pos = foodObj.getPos();

        for (int x = static_cast<int>(pos.x) - foodEffectSize; x < static_cast<int>(pos.x) + foodEffectSize; ++x)
        {
            for (int y = static_cast<int>(pos.y) - foodEffectSize; y < static_cast<int>(pos.y) + foodEffectSize; ++y)
            {
                size_t index = indexFromPos(x, y);
                float dx1 = ECSE::wrapDifference(static_cast<float>(pos.x), 
                        static_cast<float>(x),
                        static_cast<float>(width)),
                    dy1 = ECSE::wrapDifference(static_cast<float>(pos.y),
                        static_cast<float>(y),
                        static_cast<float>(height));
                float dist = sqrt(dx1 * dx1 + dy1 * dy1);

                if (dist == 0.f) cells[index].birthChance = 1.f;
                else
                {
                    cells[index].birthChance = std::max(cells[index].birthChance, ECSE::clamp(0.f, 1.f, foodStrength / (dist * dist)));
                }
            }
        }
    }

    const int vortexEffectSize = 10;
    const float vortexStrength = 12.5f;
    // Increase likelihood of cells being born near vortex
    for (auto& vortexObj : vortices) {
        sf::Vector2i pos = vortexObj.getPos();

        for (int x = static_cast<int>(pos.x) - vortexEffectSize; x < static_cast<int>(pos.x) + vortexEffectSize; ++x)
        {
            for (int y = static_cast<int>(pos.y) - vortexEffectSize; y < static_cast<int>(pos.y) + vortexEffectSize; ++y)
            {
                size_t index = indexFromPos(x, y);
                float dx1 = ECSE::wrapDifference(static_cast<float>(pos.x),
                    static_cast<float>(x),
                    static_cast<float>(width)),
                    dy1 = ECSE::wrapDifference(static_cast<float>(pos.y),
                    static_cast<float>(y),
                    static_cast<float>(height));
                float dist = sqrt(dx1 * dx1 + dy1 * dy1);

                if (dist == 0.f) cells[index].birthChance = 1.f;
                else
                {
                    cells[index].birthChance = std::max(cells[index].birthChance, ECSE::clamp(0.f, 1.f, vortexStrength / (dist * dist)));
                }
            }
        }
    }
}
예제 #8
0
/**
 * Update the aim screen.
 * @returns	bool true if the player has fired, false otherwise
 */
bool updateAim() {
    float vert = joyReadF(true), horiz = joyReadF(false);
    bool updated = false;
    if(vert < -joyThreshold && aimY > 0) {
        aimY--;
        updated = true;
    }
    else if(vert > joyThreshold && aimY < MAP_SIZE - 1) {
        aimY++;
        updated = true;
    }

    if(horiz < -joyThreshold && aimX > 0) {
        aimX--;
        updated = true;
    }
    else if(horiz > joyThreshold && aimX < MAP_SIZE - 1) {
        aimX++;
        updated = true;
    }

    if (updated) {
        renderMap(&enemyMap);
        renderCursor(aimX, aimY);
    }

    if(buttonAPressed() && getState(enemyMap.squares[indexFromPos(aimX, aimY)]) == Map::UNKNOWN) {
        // Fire the shot!
        listenUntil(ENQ);
        sendPosition(aimX, aimY);

        // Get back a response
        bool hit = false;
        Ship::TYPES type = Ship::NONE;
        getResponse(&hit, &type);
        Serial.print("Hit: ");//DEBUG
        Serial.println(hit);//DEBUG
        Serial.print("Type: ");//DEBUG
        Serial.println(getTypeName(type));//DEBUG

        if (hit) {
            if (type != Ship::NONE) {
                String name = getTypeName(type);
                enemyMap.ships[getShipIndex(type)].health = 0;
                String message[] = {"You sunk the enemy's", name + "!"};
                renderMessage(message, 2);
            } else {
                String message[] = {"You hit!"};

                renderMessage(message, 1);
            }
        } else {
            String message[] = {"You missed!"};
            renderMessage(message, 1);
        }

        setState(&enemyMap.squares[indexFromPos(aimX, aimY)], hit ? Map::HIT : Map::MISS);
        renderMap(&enemyMap);
        renderCursor(aimX, aimY);

        while (!buttonAPressed()) {}

        return true;
    }
    return false;
}