|
/*
|
|
* Copyright (C) 2021 Christopher J. Howard
|
|
*
|
|
* This file is part of Antkeeper source code.
|
|
*
|
|
* Antkeeper source code is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Antkeeper source code is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "game/ant/swarm.hpp"
|
|
#include "game/component/transform.hpp"
|
|
#include "game/component/steering.hpp"
|
|
#include "game/component/model.hpp"
|
|
#include "game/component/picking.hpp"
|
|
#include "resources/resource-manager.hpp"
|
|
#include "math/quaternion.hpp"
|
|
#include "config.hpp"
|
|
#include <cmath>
|
|
#include <random>
|
|
|
|
namespace game {
|
|
namespace ant {
|
|
|
|
/**
|
|
* Generates a random point in a unit sphere.
|
|
*
|
|
* @see https://math.stackexchange.com/questions/87230/picking-random-points-in-the-volume-of-sphere-with-uniform-probability/87238#87238
|
|
*/
|
|
template <class T, class Generator>
|
|
static math::vector3<T> sphere_random(Generator& rng)
|
|
{
|
|
const std::uniform_real_distribution<T> distribution(T{-1}, T{1});
|
|
|
|
math::vector3<T> position;
|
|
for (std::size_t i = 0; i < 3; ++i)
|
|
position[i] = distribution(rng);
|
|
|
|
return math::normalize(position) * std::cbrt(distribution(rng));
|
|
}
|
|
|
|
entity::id create_swarm(game::context& ctx)
|
|
{
|
|
// Determine swarm properties
|
|
const float3 swarm_center = {0, 100, 0};
|
|
const float swarm_radius = 25.0f;
|
|
const std::size_t male_count = 50;
|
|
const std::size_t queen_count = 50;
|
|
const std::size_t alate_count = male_count + queen_count;
|
|
|
|
const float3 male_scale = {0.5, 0.5, 0.5};
|
|
const float3 queen_scale = {1, 1, 1};
|
|
|
|
// Init transform component
|
|
game::component::transform transform;
|
|
transform.local = math::transform<float>::identity;
|
|
transform.world = transform.local;
|
|
transform.warp = true;
|
|
|
|
// Init picking component
|
|
game::component::picking picking;
|
|
picking.sphere = {float3{0, 0, 0}, 0.5f * 2.0f};
|
|
std::uint32_t male_picking_flags = 0b01;
|
|
std::uint32_t queen_picking_flags = 0b10;
|
|
|
|
// Create swarm entity
|
|
entity::id swarm_eid = ctx.entity_registry->create();
|
|
transform.local.translation = swarm_center;
|
|
transform.world = transform.local;
|
|
transform.warp = true;
|
|
ctx.entity_registry->emplace<game::component::transform>(swarm_eid, transform);
|
|
|
|
// Init male model component
|
|
game::component::model male_model;
|
|
male_model.render_model = ctx.resource_manager->load<render::model>("male-boid.mdl");
|
|
male_model.instance_count = 0;
|
|
male_model.layers = 1;
|
|
|
|
// Init queen model component
|
|
game::component::model queen_model;
|
|
queen_model.render_model = ctx.resource_manager->load<render::model>("queen-boid.mdl");
|
|
queen_model.instance_count = 0;
|
|
queen_model.layers = 1;
|
|
|
|
// Init steering component
|
|
game::component::steering steering;
|
|
steering.agent.mass = 1.0f;
|
|
steering.agent.velocity = {0, 0, 0};
|
|
steering.agent.acceleration = {0, 0, 0};
|
|
steering.agent.max_force = 4.0f;
|
|
steering.agent.max_speed = 5.0f;
|
|
steering.agent.max_speed_squared = steering.agent.max_speed * steering.agent.max_speed;
|
|
steering.agent.orientation = math::quaternion<float>::identity();
|
|
steering.agent.forward = steering.agent.orientation * config::global_forward;
|
|
steering.agent.up = steering.agent.orientation * config::global_up;
|
|
steering.wander_weight = 1.0f;
|
|
steering.wander_noise = math::radians(2000.0f);
|
|
steering.wander_distance = 10.0f;
|
|
steering.wander_radius = 8.0f;
|
|
steering.wander_angle = 0.0f;
|
|
steering.wander_angle2 = 0.0f;
|
|
steering.seek_weight = 0.2f;
|
|
steering.seek_target = swarm_center;
|
|
steering.flee_weight = 0.0f;
|
|
steering.sum_weights = steering.wander_weight + steering.seek_weight + steering.flee_weight;
|
|
|
|
// Construct and seed random number generator
|
|
std::random_device seed;
|
|
std::mt19937 rng(seed());
|
|
|
|
// Create alates
|
|
for (std::size_t i = 0; i < alate_count; ++i)
|
|
{
|
|
// Generate random position in swarm sphere
|
|
steering.agent.position = swarm_center + sphere_random<float>(rng) * swarm_radius;
|
|
transform.local.translation = steering.agent.position;
|
|
|
|
entity::id alate_eid = ctx.entity_registry->create();
|
|
ctx.entity_registry->emplace<game::component::steering>(alate_eid, steering);
|
|
|
|
if (i < male_count)
|
|
{
|
|
// Create male
|
|
ctx.entity_registry->emplace<game::component::model>(alate_eid, male_model);
|
|
|
|
transform.local.scale = male_scale;
|
|
transform.world = transform.local;
|
|
ctx.entity_registry->emplace<game::component::transform>(alate_eid, transform);
|
|
|
|
picking.flags = male_picking_flags;
|
|
ctx.entity_registry->emplace<game::component::picking>(alate_eid, picking);
|
|
}
|
|
else
|
|
{
|
|
// Create queen
|
|
ctx.entity_registry->emplace<game::component::model>(alate_eid, queen_model);
|
|
|
|
transform.local.scale = queen_scale;
|
|
transform.world = transform.local;
|
|
ctx.entity_registry->emplace<game::component::transform>(alate_eid, transform);
|
|
|
|
picking.flags = queen_picking_flags;
|
|
ctx.entity_registry->emplace<game::component::picking>(alate_eid, picking);
|
|
}
|
|
}
|
|
|
|
return swarm_eid;
|
|
}
|
|
|
|
void destroy_swarm(game::context& ctx, entity::id swarm_eid)
|
|
{
|
|
// Destroy alates
|
|
auto view = ctx.entity_registry->view<game::component::steering>();
|
|
ctx.entity_registry->destroy(view.begin(), view.end());
|
|
|
|
// Destroy swarm
|
|
ctx.entity_registry->destroy(swarm_eid);
|
|
}
|
|
|
|
} // namespace ant
|
|
} // namespace game
|