|
|
@ -2,7 +2,7 @@ |
|
|
|
|
|
|
|
void Bullet::setup(){ |
|
|
|
/* setup camera & world */ |
|
|
|
camera_start_pos = ofVec3f(0, -3.f, -40.f); |
|
|
|
camera_start_pos = ofVec3f(0, 0, -40.f); |
|
|
|
camera_end_position = glm::vec3(ofRandom(-100, 100), ofRandom(-100, 100), ofRandom(0, 0)); |
|
|
|
camera_move_duration = 20.f; |
|
|
|
camera_move_start_time = ofGetElapsedTimef(); |
|
|
@ -35,7 +35,12 @@ void Bullet::update(bool& is_controller_active, Node& chosen_node, vector<Node*> |
|
|
|
|
|
|
|
nn_nodes = nn; |
|
|
|
|
|
|
|
static float blend_factor = 0.0f; |
|
|
|
float current_zoom = camera.getScale().x; |
|
|
|
const float MIN_ZOOM = 0.04f; |
|
|
|
const float MAX_ZOOM = 0.3f; |
|
|
|
const float ZOOM_OUT_START_TIME = 40.0f; |
|
|
|
float d_time = ofGetLastFrameTime(); |
|
|
|
float target_zoom = 0; |
|
|
|
|
|
|
|
contr_active = is_controller_active; |
|
|
|
|
|
|
@ -46,129 +51,49 @@ void Bullet::update(bool& is_controller_active, Node& chosen_node, vector<Node*> |
|
|
|
time_at_target = 0; |
|
|
|
random_walk_time = 0; |
|
|
|
scale_out_factor = 0; |
|
|
|
camera_velocity = glm::vec3(0.0f); |
|
|
|
} else { |
|
|
|
new_chosen_node = false; |
|
|
|
time_at_target += d_time; |
|
|
|
} |
|
|
|
|
|
|
|
cameraBounds = getCameraBounds(camera); |
|
|
|
world.update(); |
|
|
|
|
|
|
|
float d_time = ofGetLastFrameTime(); |
|
|
|
|
|
|
|
glm::vec3 target_pos = chosen_node.collider->getPosition(); |
|
|
|
glm::vec3 current_pos = camera.getPosition(); |
|
|
|
glm::vec3 dir = current_pos - target_pos; |
|
|
|
float dist = glm::length(dir); |
|
|
|
|
|
|
|
|
|
|
|
// Check if we're close to target
|
|
|
|
if (dist < TARGET_REACHED_DISTANCE) { |
|
|
|
time_at_target += d_time; |
|
|
|
|
|
|
|
// Start random walk after delay
|
|
|
|
if (time_at_target >= RANDOM_WALK_DELAY && !is_random_walking) { |
|
|
|
is_random_walking = true; |
|
|
|
random_target = generateRandomTarget(); |
|
|
|
} |
|
|
|
} else { |
|
|
|
time_at_target = 0.0f; |
|
|
|
// Start random walk after delay
|
|
|
|
if (time_at_target >= RANDOM_WALK_DELAY && !is_random_walking) { |
|
|
|
is_random_walking = true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Handle random walk mode
|
|
|
|
if (is_random_walking) { |
|
|
|
target_zoom = MAX_ZOOM; |
|
|
|
random_walk_time += d_time; |
|
|
|
|
|
|
|
glm::vec3 to_random_target = random_target - current_pos; |
|
|
|
float random_dist = glm::length(to_random_target); |
|
|
|
|
|
|
|
// Generate new random target when reached current one
|
|
|
|
if (random_dist < 10.0f) { |
|
|
|
random_target = generateRandomTarget(); |
|
|
|
} |
|
|
|
|
|
|
|
// Smooth movement towards random target
|
|
|
|
if (random_dist > 0.0001f) { |
|
|
|
glm::vec3 random_dir = glm::normalize(to_random_target); |
|
|
|
camera_velocity = random_dir * RANDOM_WALK_SPEED * d_time; |
|
|
|
} |
|
|
|
} else { |
|
|
|
target_zoom = MIN_ZOOM; |
|
|
|
} |
|
|
|
// Regular movement towards chosen node
|
|
|
|
else if (!std::isnan(dist) && dist >= 0.0001f) { |
|
|
|
|
|
|
|
glm::vec3 norm_dir = glm::normalize(dir); |
|
|
|
|
|
|
|
if(!std::isnan(norm_dir.x) && !std::isnan(norm_dir.y) && !std::isnan(norm_dir.z)) { |
|
|
|
|
|
|
|
float distance_factor = glm::min(dist / 50.0f, 1.0f); |
|
|
|
float current_acceleration = ACCELERATION * distance_factor; |
|
|
|
glm::vec3 acceleration = -norm_dir * current_acceleration * d_time; |
|
|
|
|
|
|
|
if(!std::isnan(acceleration.x) && !std::isnan(acceleration.y) && !std::isnan(acceleration.z)) { |
|
|
|
camera_velocity += acceleration; |
|
|
|
} |
|
|
|
|
|
|
|
/* decelerate if close to target */ |
|
|
|
if (dist < 5.0f) { |
|
|
|
float decel_factor = dist / 5.0f; |
|
|
|
camera_velocity *= (1.0f - (1.0f - decel_factor) * d_time * 10.0f); |
|
|
|
} |
|
|
|
|
|
|
|
float mag = glm::length(camera_velocity); |
|
|
|
current_zoom += (target_zoom - camera.getScale().x) * 0.005f; |
|
|
|
|
|
|
|
/* clamp vel */ |
|
|
|
if (mag > MAX_VELOCITY) { |
|
|
|
camera_velocity = glm::normalize(camera_velocity) * MAX_VELOCITY; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
camera.setScale(current_zoom); |
|
|
|
|
|
|
|
// Smoothed zoom based on velocity
|
|
|
|
float vel_magnitude = glm::length(camera_velocity); |
|
|
|
static float current_zoom = 0.02f; |
|
|
|
float target_zoom = ofMap(vel_magnitude, 0, MAX_VELOCITY, 0.02, 0.3, true); |
|
|
|
current_zoom = current_zoom + (target_zoom - current_zoom) * 0.05f; |
|
|
|
|
|
|
|
// Calculate scale-out factor if we're in random walk mode
|
|
|
|
if (random_walk_time > SCALE_OUT_START_TIME) { |
|
|
|
float scale_progress = (random_walk_time - SCALE_OUT_START_TIME) / SCALE_OUT_DURATION; |
|
|
|
scale_progress = ofClamp(scale_progress, 0.0f, 1.0f); |
|
|
|
|
|
|
|
// Smoother easing function (quintic ease in/out)
|
|
|
|
float t = scale_progress; |
|
|
|
if (t < 0.5f) { |
|
|
|
scale_out_factor = 16 * t * t * t * t * t; |
|
|
|
} else { |
|
|
|
t = t - 1; |
|
|
|
scale_out_factor = 1 + 16 * t * t * t * t * t; |
|
|
|
} |
|
|
|
if(!glm::any(glm::isnan((target_pos)))){ |
|
|
|
glm::vec3 new_pos = current_pos + (target_pos - current_pos) * 0.01f; |
|
|
|
new_pos.z = current_pos.z; |
|
|
|
camera.setPosition(new_pos); |
|
|
|
} |
|
|
|
|
|
|
|
// Blend between velocity-based zoom and scale-out with smooth transitions both ways
|
|
|
|
float final_scale = current_zoom; |
|
|
|
|
|
|
|
// Calculate target blend based on whether we're random walking
|
|
|
|
float target_blend = is_random_walking ? scale_out_factor : 0.0f; |
|
|
|
blend_factor += (target_blend - blend_factor) * 0.05f; // Smooth transition both ways
|
|
|
|
|
|
|
|
if (blend_factor > 0.001f) { // Apply blended scale if we have any blend factor
|
|
|
|
final_scale = ofLerp(current_zoom, 0.3, blend_factor); |
|
|
|
if(glm::any(glm::isnan(camera.getPosition()))){ |
|
|
|
camera.setPosition(0, 0, -40); |
|
|
|
} |
|
|
|
|
|
|
|
camera.setScale(final_scale); |
|
|
|
|
|
|
|
// Update camera position
|
|
|
|
glm::vec3 new_pos = current_pos + camera_velocity * d_time; |
|
|
|
|
|
|
|
// Clamp position within bounds
|
|
|
|
new_pos.x = ofClamp(new_pos.x, -RANDOM_WALK_RADIUS, RANDOM_WALK_RADIUS); |
|
|
|
new_pos.y = ofClamp(new_pos.y, -RANDOM_WALK_RADIUS, RANDOM_WALK_RADIUS); |
|
|
|
|
|
|
|
camera.setPosition(new_pos); |
|
|
|
|
|
|
|
// Always update these regardless of camera movement
|
|
|
|
for(auto& node : nodes) { |
|
|
|
updateNodeActivation(node); |
|
|
|
} |
|
|
|
|
|
|
|
last_chosen_node = chosen_node; |
|
|
|
} |
|
|
@ -193,14 +118,13 @@ void Bullet::draw(){ |
|
|
|
if(checkNodeVisibility(n)){ |
|
|
|
// Compare pointers directly
|
|
|
|
bool is_nearest = false; |
|
|
|
for(const auto* nn : nn_nodes) { |
|
|
|
for(const auto* nn : nn_nodes) { |
|
|
|
if(nn->tsne_position == n.tsne_position) { // or if you store the address differently, adjust this comparison
|
|
|
|
is_nearest = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
ofPushStyle(); |
|
|
|
|
|
|
|
ofSetColor(ofColor::orange); // Yellow for others
|
|
|
|
ofPushMatrix(); |
|
|
|
n.collider->transformGL(); |
|
|
@ -275,12 +199,13 @@ void Bullet::addMesh(ofMesh _mesh, ofMesh _simple_mesh, Node& _node){ |
|
|
|
ofQuaternion startRot = ofQuaternion(0., 0., 0., PI); |
|
|
|
|
|
|
|
|
|
|
|
ofVec3f start_location = ofVec3f( ofRandom(_node.tsne_position.x - 50, _node.tsne_position.x + 50) + 20, ofRandom(_node.tsne_position.y - 50, _node.tsne_position.y + 50) + 20, -5 ); |
|
|
|
ofVec3f start_location = ofVec3f( ofRandom(_node.tsne_position.x - 50, _node.tsne_position.x + 50), ofRandom(_node.tsne_position.y - 50, _node.tsne_position.y + 50) , -5 ); |
|
|
|
|
|
|
|
ofxBulletCustomShape* s = new ofxBulletCustomShape(); |
|
|
|
s->addMesh(_simple_mesh, _node.scale * 1.4, true); |
|
|
|
s->create( world.world, start_location, startRot, 3.); |
|
|
|
s->add(); |
|
|
|
s->getRigidBody()->setActivationState(DISABLE_DEACTIVATION); |
|
|
|
s->getRigidBody()->setAngularFactor(btVector3(0, 0, 1)); |
|
|
|
s->getRigidBody()->setDamping(btScalar(0.0), btScalar(0.0)); |
|
|
|
s->getRigidBody()->setLinearFactor(btVector3(1, 1, 0)); |
|
|
@ -318,7 +243,7 @@ void Bullet::updateShapeBatch(size_t start, size_t end) { |
|
|
|
float dist_sq = glm::length(direction); |
|
|
|
glm::vec3 norm_dir = glm::normalize(direction); |
|
|
|
glm::vec3 rand_vel(ofRandom(-1, 1)); |
|
|
|
nodes[i].collider->applyCentralForce((1.0f * norm_dir) + rand_vel); |
|
|
|
nodes[i].collider->applyCentralForce((1.0f * norm_dir)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -379,10 +304,10 @@ void Bullet::updateTSNEPosition(vector<Node>& _nodes){ |
|
|
|
/* check if a node is inside a given radius, deactivate & stall if not. if it drifts too far reset position*/ |
|
|
|
void Bullet::updateNodeActivation(Node& node) { |
|
|
|
glm::vec3 node_pos = node.collider->getPosition(); |
|
|
|
bool should_be_active = (node_pos.x < cameraBounds.x + 20 && |
|
|
|
node_pos.x > cameraBounds.y - 20 && |
|
|
|
node_pos.y < cameraBounds.z + 20 && |
|
|
|
node_pos.y > cameraBounds.w - 20); |
|
|
|
bool should_be_active = (node_pos.x < cameraBounds.x + 100 && |
|
|
|
node_pos.x > cameraBounds.y -100 && |
|
|
|
node_pos.y < cameraBounds.z + 100 && |
|
|
|
node_pos.y > cameraBounds.w - 100); |
|
|
|
|
|
|
|
btRigidBody* body = node.collider->getRigidBody(); |
|
|
|
if (should_be_active && !body->isActive()) { |
|
|
|