void Octree::split() { float subX = bounds.cent.x; float subY = bounds.cent.y; float subZ = bounds.cent.z; Moo::Vector3D halfD = bounds.cent - bounds.min; int nextLevel = level + 1; //lower layer cells(0-3) Moo::BoundingBox box0(bounds.min, bounds.cent); std::shared_ptr<Octree> oct0 = std::make_shared<Octree>(nextLevel, box0, &*this, this->cr); Moo::Vector3D box1Min(bounds.min.x, bounds.min.y, bounds.cent.z); Moo::Vector3D box1Max = box1Min + halfD; Moo::BoundingBox box1(box1Min, box1Max); std::shared_ptr<Octree> oct1 = std::make_shared<Octree>(nextLevel, box1, &*this, this->cr); Moo::Vector3D box2Min(bounds.cent.x, bounds.min.y, bounds.cent.z); Moo::Vector3D box2Max = box2Min + halfD; Moo::BoundingBox box2(box2Min, box2Max); std::shared_ptr<Octree> oct2 = std::make_shared<Octree>(nextLevel, box2, &*this, this->cr); Moo::Vector3D box3Min(bounds.cent.x, bounds.min.y, bounds.min.z); Moo::Vector3D box3Max = box3Min + halfD; Moo::BoundingBox box3(box3Min, box3Max); std::shared_ptr<Octree> oct3 = std::make_shared<Octree>(nextLevel, box3, &*this, this->cr); //upper layer cells(4-7) Moo::Vector3D box4Min(bounds.min.x, bounds.cent.y, bounds.min.z); Moo::Vector3D box4Max = box4Min + halfD; Moo::BoundingBox box4(box4Min, box4Max); std::shared_ptr<Octree> oct4 = std::make_shared<Octree>(nextLevel, box4, &*this, this->cr); Moo::Vector3D box5Min(bounds.min.x, bounds.cent.y, bounds.cent.z); Moo::Vector3D box5Max = box5Min + halfD; Moo::BoundingBox box5(box5Min, box5Max); std::shared_ptr<Octree> oct5 = std::make_shared<Octree>(nextLevel, box5, &*this, this->cr); Moo::Vector3D box6Min = bounds.cent; Moo::Vector3D box6Max = bounds.max; Moo::BoundingBox box6(box6Min, box6Max); std::shared_ptr<Octree> oct6 = std::make_shared<Octree>(nextLevel, box6, &*this, this->cr); Moo::Vector3D box7Min(bounds.cent.x, bounds.cent.y, bounds.min.z); Moo::Vector3D box7Max = box7Min + bounds.cent; Moo::BoundingBox box7(box7Min, box7Max); std::shared_ptr<Octree> oct7 = std::make_shared<Octree>(nextLevel, box7, &*this, this->cr); childNode[0] = oct0; childNode[1] = oct1; childNode[2] = oct2; childNode[3] = oct3; childNode[4] = oct4; childNode[5] = oct5; childNode[6] = oct6; childNode[7] = oct7; }
//============================================================================== bool GameServer::IsPositionWrong(float x, float y, Actor* actor) { if (levelMap_.GetCell(x, y) != '.') { return true; } if (levelMap_.GetCell(x + 0.4f, y) != '.' || levelMap_.GetCell(x - 0.4f, y) != '.' || levelMap_.GetCell(x, y - 0.4f) != '.' || levelMap_.GetCell(x, y + 0.4f) != '.') { return true; } for (auto p : actors_) { if (p == actor || p->GetType() == EActorType::ITEM) { continue; } if (p->GetPosition().x >= 0 && p->GetPosition().y >= 0) { Box box0(actor->GetPosition(), actor->GetSize(), actor->GetSize()); Box box1(p->GetPosition(), p->GetSize(), p->GetSize()); if (box0.Intersect(box1)) { return true; } } } return false; }
//============================================================================== void GameServer::tick() { /*float dt = (time_.elapsed() - lastTime_) * 0.001f;*/ lastTime_ = time_.elapsed(); /*if (actors_.size() < 100 && !testingStageActive_) { GenMonsters_(); }*/ auto collideWithGrid = [=](Actor* actor, EActorDirection direction) { auto& p = *actor; float x = p.GetPosition().x; float y = p.GetPosition().y; bool collided = false; if ((levelMap_.GetCell(x + 0.49f, y - 0.51f) != '.' || levelMap_.GetCell(x + 0.49f, y + 0.49f) != '.') && levelMap_.GetCell(x - slideThreshold_+ 0.5f, y) == '.' && (direction == EActorDirection::NORTH || direction == EActorDirection::SOUTH)) { p.SetPosition(Vector2(x - slideThreshold_+ 0.0001f, p.GetPosition().y)); } if (levelMap_.GetCell(x + slideThreshold_- 0.5f, y) == '.' &&((levelMap_.GetCell(x - 0.5f, y - 0.51f) != '.' || levelMap_.GetCell(x - 0.5f, y + 0.49f) != '.') && (direction == EActorDirection::NORTH || direction == EActorDirection::SOUTH))) { p.SetPosition(Vector2(x + slideThreshold_- 0.0001f, p.GetPosition().y)); } if (levelMap_.GetCell(x, y - slideThreshold_ + 0.5f) == '.' && (levelMap_.GetCell(x - 0.51f, y + 0.49f) != '.' || levelMap_.GetCell(x + 0.49f, y + 0.49f) != '.') && (direction == EActorDirection::EAST || direction == EActorDirection::WEST)) { p.SetPosition(Vector2(p.GetPosition().x, y - slideThreshold_+ 0.0001f)); } if ((levelMap_.GetCell(x + 0.49f, y - 0.5f) != '.' || levelMap_.GetCell(x - 0.51f, y - 0.5f) != '.') && levelMap_.GetCell(x, y + slideThreshold_- 0.5f) == '.' && (direction == EActorDirection::EAST || direction == EActorDirection::WEST)) { p.SetPosition(Vector2(p.GetPosition().x, y + slideThreshold_ - 0.001f)); } if (levelMap_.GetCell(x + 0.5f, y) != '.') { p.SetPosition(Vector2(round(x + 0.5f) - 0.5f, p.GetPosition().y)); collided = true; } if (levelMap_.GetCell(x - 0.51f, y) != '.') { p.SetPosition(Vector2(round(x - 0.5f) + 0.5f, p.GetPosition().y)); collided = true; } if (levelMap_.GetCell(x, y + 0.5f) != '.') { p.SetPosition(Vector2(p.GetPosition().x, round(y + 0.5f) - 0.5f)); collided = true; } if (levelMap_.GetCell(x, y - 0.51f) != '.') { p.SetPosition(Vector2(p.GetPosition().x, round(y - 0.5f) + 0.5f)); collided = true; } if (collided) { actor->OnCollideWorld(); } }; for (Actor* actor: actors_) { if (actor->GetType() == EActorType::MONSTER) { Monster* monster = dynamic_cast<Monster*>(actor); Creature* target = monster->target; float distance2; Vector2 m_pos = actor->GetPosition(); if (target && target != nullptr) { Vector2 t_pos = target->GetPosition(); distance2 = Sqr(m_pos.x - t_pos.x) + Sqr(m_pos.y - t_pos.y); if (distance2 < 25) { if (abs(m_pos.x - t_pos.x - 1.0f) < playerVelocity_ && m_pos.x - t_pos.x - 1.0f != 0) { monster->SetPosition(Vector2(t_pos.x + 1.0f, m_pos.y)); monster->SetDirection(EActorDirection::NONE); } if (abs(m_pos.y - t_pos.y + 1.0f) < playerVelocity_ && m_pos.y - t_pos.y + 1.0f != 0) { monster->SetPosition(Vector2(m_pos.x, t_pos.y - 1.0f)); monster->SetDirection(EActorDirection::NONE); } if (m_pos.x < t_pos.x - 1.0f) { monster->SetDirection(EActorDirection::EAST); } else if (m_pos.x > t_pos.x + 1.0f) { monster->SetDirection(EActorDirection::WEST); } else if (m_pos.y < t_pos.y - 1.0f) { monster->SetDirection(EActorDirection::SOUTH); } else if (m_pos.y > t_pos.y + 1.0f) { monster->SetDirection(EActorDirection::NORTH); } } } if (!target || target == nullptr || distance2 >= 5) { for (Actor* tar : actors_) { if (tar != monster) { bool b = false; if (tar->GetType() != EActorType::ITEM && tar->GetType () != EActorType::PROJECTILE) { Creature* m = dynamic_cast<Creature*>(tar); QStringList str = monster->Flags.filter("HATE"); for (QString hate: str) { if (Hates[hate] == m->GetRace()) { b = true; break; } } if (b) { Vector2 t_pos = tar->GetPosition(); distance2 = Sqr(m_pos.x - t_pos.x) + Sqr(m_pos.y - t_pos.y); // Dasha told 5^2 is a protocol defined const if (distance2 < 25) { monster->target = m; break; } } } } } } } if (actor->GetType() == EActorType::MONSTER || actor->GetType() == EActorType::PLAYER) { Creature* monster = dynamic_cast<Creature*>(actor); if (monster->GetHealth() <= 0) { KillActor_(actor); break; } } } for (Actor* actor: actors_) { if (!actor || actor == nullptr) { break; } auto v = directionToVector[static_cast<unsigned>(actor->GetDirection())] ; actor->SetVelocity(v); float dt = playerVelocity_; Vector2 old_pos = actor->GetPosition(); Vector2 new_pos = old_pos + v * (dt + 0.001); Vector2 old_pos2 = old_pos + v * 0.51; levelMap_.RemoveActor(actor); EActorDirection d = actor->GetDirection(); float x = new_pos.x; float y = new_pos.y; if (levelMap_.GetCell(old_pos2.x, old_pos2.y) != '#' && d != EActorDirection::NONE && (((levelMap_.GetCell(x - slideThreshold_+ 0.5f, y) == '.' && levelMap_.GetCell(x + slideThreshold_- 0.5f, y) == '.') && (d == EActorDirection::NORTH || d == EActorDirection::SOUTH)) || ((levelMap_.GetCell(x, y - slideThreshold_+ 0.5f) == '.' && levelMap_.GetCell(x, y + slideThreshold_- 0.5f) == '.') && (d == EActorDirection::EAST || d == EActorDirection::WEST)))) { if (levelMap_.GetCell(new_pos.x, new_pos.y) == '.') { if (!actor->Update(dt) && actor->GetType () == EActorType::PROJECTILE) { static_cast<Projectile*>(actor)->death = true; } collideWithGrid(actor, d); } else if (levelMap_.GetCell(x , y) != '.' && playerVelocity_ >= 1) { bool b = false; for (float i = 0.01; i <= dt; i += 0.01) { new_pos = old_pos + v * i + v * 0.5f; if (levelMap_.GetCell(new_pos.x, new_pos.y) == '#' && !b) { actor->Update(i - 0.01); b = true; } } } else { if (actor->GetType () == EActorType::PROJECTILE) { static_cast<Projectile*>(actor)->death = true; } } } else { if (actor && actor != nullptr) { if (actor->GetType () == EActorType::PROJECTILE) { static_cast<Projectile*>(actor)->death = true; } else { actor->OnCollideWorld(); } } } if (actor->GetType() == EActorType::PLAYER) { Player* player = dynamic_cast<Player*>(actor); if (player->GetHealth() < player->GetMaxHealth()) { player->SetHealth(player->GetHealth() + 1); } } if (actor->GetType() == EActorType::MONSTER) { Monster* monster = dynamic_cast<Monster*>(actor); Creature* target = monster->target; if (target && target->GetHealth() > 0) { Vector2 m_pos = actor->GetPosition(); Vector2 t_pos = target->GetPosition(); float distance2 = Sqr(m_pos.x - t_pos.x) + Sqr(m_pos.y - t_pos.y); if (distance2 <= Sqr(pickUpRadius_)) { events_ << monster->atack(target); events_ << target->atack(monster); } } } for (Actor* neighbour : actors_) { if (actor == nullptr || neighbour == nullptr || actor == neighbour || neighbour->GetType() == EActorType::ITEM || (actor->GetType() == EActorType::PROJECTILE && neighbour->GetType() == EActorType::PROJECTILE)) { break; } Box box0(neighbour->GetPosition(), 0.9f, 0.9f); Box box1(actor->GetPosition(), 0.9f, 0.9f); if (box0.Intersect(box1)) { actor->OnCollideActor(neighbour); neighbour->OnCollideActor(actor); if (actor->GetType() == EActorType::PROJECTILE) { static_cast<Projectile*>(actor)->death = true; if (neighbour->GetType () == EActorType::MONSTER) { Monster* monster = dynamic_cast<Monster*>(neighbour); if (monster->GetHealth () <= 0) { GetItems(monster); } } } else if (neighbour->GetType() == EActorType::PROJECTILE) { static_cast<Projectile*>(neighbour)->death = true; if (actor->GetType() == EActorType::MONSTER) { Monster* monster = dynamic_cast<Monster*>(actor); if (monster->GetHealth () <= 0) { GetItems(monster); } } } else if (neighbour->GetType() != EActorType::ITEM) { actor->SetPosition(old_pos); } } } if (actor->GetType() == EActorType::PROJECTILE && static_cast<Projectile*>(actor)->death) { QVariantMap ans1; ans1["radius"] = 1.0f; ans1["x"] = actor->GetPosition ().x; ans1["y"] = actor->GetPosition ().y; QVariantMap ans; ans["explode"] = ans1; events_ << ans; idToActor_.erase(actor->GetId()); actors_.erase(std::remove(actors_.begin(), actors_.end(), actor), actors_.end()); delete actor; actor = nullptr; } else { levelMap_.IndexActor(actor); } } QVariantMap tickMessage; tickMessage["tick"] = tick_; tickMessage["events"] = events_; events_.clear(); emit broadcastMessage(QString(QJsonDocument::fromVariant(tickMessage).toJson())); tick_++; }