#include #include #include #include #include #include #include #include #include "traffic.h" Traffic::Traffic(): max_spawn_distance(120.0f), min_spawn_distance(80), delete_distance(Vector3(100.0f, -60.0f, 180.0f)), physics_distance(Vector3(30.0f, -20.0f, 60.0f)), list_cooldown(0.0), debug(false) { state = 0; rnd.instance(); rnd->randomize(); call_deferred("idle_runner"); } Traffic::~Traffic() { } void Traffic::_bind_methods() { ClassDB::bind_method(D_METHOD("idle_runner"), &Traffic::idle_runner); ClassDB::bind_method(D_METHOD("add_traffic_vehicle", "scene"), &Traffic::add_traffic_vehicle); ClassDB::bind_method(D_METHOD("remove_traffic_vehicle", "scene"), &Traffic::remove_traffic_vehicle); } void Traffic::add_traffic_vehicle(Ref scene) { scenes.push_back(scene); printf("traffic: added_scene: %d\n", scenes.size()); } void Traffic::remove_traffic_vehicle(Ref scene) { scenes.erase(scene); printf("traffic: removed_scene: %d\n", scenes.size()); } void Traffic::idle_runner() { uint64_t before, after; float delta; SceneTree *tree = SceneTree::get_singleton(); Viewport *view; Camera *camera; Transform cam_xform; before = OS::get_singleton()->get_ticks_usec(); assert(tree); delta = tree->get_idle_process_time(); if (state > 0 && debug) debug_traffic(); if (state > 0) control_traffic(); switch(state) { case 0: debug_mat.instance(); debug_mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); debug_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); debug_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); instance = VS::get_singleton()->instance_create(); VS::get_singleton()->instance_set_scenario(instance, tree->get_root()->get_world()->get_scenario()); immediate = VS::get_singleton()->immediate_create(); VisualServer::get_singleton()->instance_set_base(instance, immediate); VS::get_singleton()->immediate_set_material(immediate, debug_mat->get_rid()); tree->connect("idle_frame", this, "idle_runner"); state = 1; break; case 1: if (list_cooldown > 0.0f) { list_cooldown -= delta; return; } tree->get_nodes_in_group("traffic_spawn", &spawner_list); spawner_e = spawner_list.front(); list_cooldown = 0.1f; if (spawner_list.size() > 0) state = 2; spawn_cooldown = 0.0f; break; case 2: if (scenes.size() == 0) return; if (!spawner_e) { state = 1; return; } if (spawn_cooldown > 0.0f) { spawn_cooldown -= delta; return; } view = tree->get_root(); if (!view) return; camera = view->get_camera(); if (!camera) return; cam_xform = camera->get_global_transform(); while (spawner_e) { float dst; VehicleBody *vb; Node *nscene; Spatial *sscene; Transform xform; Ref scene; Vector3 check_coordinates; after = OS::get_singleton()->get_ticks_usec(); if (after - before > 2000ULL) break; Node *spawner; Spatial *obj; spawner = spawner_e->get(); if (!spawner) goto pass_loop; if (!spawner->is_in_group("spawn")) goto pass_loop; obj = Object::cast_to(spawner); if (!obj) goto pass_loop; if (obj->has_meta("cooldown")) { float cooldown = obj->get_meta("cooldown"); cooldown -= delta; if (cooldown >= 0.0f) { obj->set_meta("cooldown", cooldown); goto pass_loop; } else obj->remove_meta("cooldown"); } xform = obj->get_global_transform(); check_coordinates = cam_xform.xform_inv(xform.origin); if (check_coordinates.z > -15.0f && check_coordinates.z < min_spawn_distance && fabsf(check_coordinates.x) < 20.0 ) goto pass_loop; dst = xform.origin.distance_squared_to(cam_xform.origin); if (check_coordinates.z > max_spawn_distance || check_coordinates.z < -50.0f || fabsf(check_coordinates.x) > 50.0f) goto pass_loop; printf("traffic: spawning scene\n"); scene = scenes[rnd->randi() % scenes.size()]; nscene = scene->instance(); sscene = Object::cast_to(nscene); view->add_child(sscene); sscene->set_global_transform(xform); sscene->add_to_group("traffic_vehicle"); sscene->set("parked", false); vb = Object::cast_to(nscene); if (vb) { vb->set_engine_force(2500.0f); vb->set_steering(0); RID space = PhysicsServer::get_singleton()->body_get_space(vb->get_rid()); vb->set_meta("space", space); PhysicsServer::get_singleton()->body_set_space(vb->get_rid(), RID()); } obj->set_meta("cooldown", 30.0f + rnd->randf() * 30.0); spawn_cooldown = 0.2f; pass_loop: spawner_e = spawner_e->next(); } break; }; } void Traffic::debug_traffic() { SceneTree *tree = SceneTree::get_singleton(); List traffic_vehicles; List::Element *e; tree->get_nodes_in_group("traffic_vehicle", &traffic_vehicles); VS::get_singleton()->immediate_clear(immediate); if (traffic_vehicles.size() == 0) return; printf("traffic: vehicles: %d\n", traffic_vehicles.size()); VS::get_singleton()->immediate_begin(immediate, VS::PRIMITIVE_LINES); for (e = traffic_vehicles.front(); e; e = e->next()) { Node *vnode = e->get(); if (!vnode) continue; Spatial *vsp = Object::cast_to(vnode); if (!vsp) continue; Transform vxform = vsp->get_global_transform(); VS::get_singleton()->immediate_color(immediate, Color(1, 0, 0, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin); VS::get_singleton()->immediate_color(immediate, Color(0, 0, 1, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin + Vector3(0, 30, 0)); if (vsp->has_meta("next_target")) { VS::get_singleton()->immediate_color(immediate, Color(1, 0, 0, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin); VS::get_singleton()->immediate_color(immediate, Color(1, 0, 0, 1)); VS::get_singleton()->immediate_vertex(immediate, vsp->get_meta("next_target")); } if (vsp->has_meta("target")) { VS::get_singleton()->immediate_color(immediate, Color(1, 0, 1, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin); VS::get_singleton()->immediate_color(immediate, Color(1, 0, 1, 1)); VS::get_singleton()->immediate_vertex(immediate, vsp->get_meta("target")); } if (vsp->has_meta("x_target")) { VS::get_singleton()->immediate_color(immediate, Color(0, 1, 0, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin); VS::get_singleton()->immediate_color(immediate, Color(0, 1, 0, 1)); Vector3 vp = vsp->get_meta("x_target"); VS::get_singleton()->immediate_vertex(immediate, vxform.xform(vp)); } if (vsp->has_meta("vel")) { VS::get_singleton()->immediate_color(immediate, Color(1, 1, 1, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin); VS::get_singleton()->immediate_color(immediate, Color(0, 0, 1, 1)); Vector3 vp = vsp->get_meta("vel"); if (vp.length_squared() == 0.0f) { vp += Vector3(0, 2, 0); } VS::get_singleton()->immediate_vertex(immediate, vxform.xform(vp)); } if (vsp->has_meta("curve")) { Ref curve = vsp->get_meta("curve"); if (curve->get_point_count() > 0) { float offt = curve->get_closest_offset(vxform.origin); float plength = curve->get_baked_length(); float pstart = CLAMP(offt - 4.0f, 0.0f, plength); Vector3 pt = curve->interpolate_baked(offt, false); VS::get_singleton()->immediate_color(immediate, Color(1, 1, 1, 1)); VS::get_singleton()->immediate_vertex(immediate, vxform.origin); VS::get_singleton()->immediate_color(immediate, Color(0, 1, 0, 1)); VS::get_singleton()->immediate_vertex(immediate, pt); while (pstart < offt + 8.0 && pstart < plength) { Vector3 opt = curve->interpolate_baked(pstart, false); float c = (pstart - offt + 4.0) / 16.0f; c = CLAMP(c, 0.0f, 1.0f); VS::get_singleton()->immediate_color(immediate, Color(1, c, c, 1)); VS::get_singleton()->immediate_vertex(immediate, opt); VS::get_singleton()->immediate_color(immediate, Color(1, c, c, 1)); VS::get_singleton()->immediate_vertex(immediate, opt + Vector3(0, 10, 0)); pstart += 1.0f; } } } } VS::get_singleton()->immediate_end(immediate); } void Traffic::control_traffic() { Viewport *view; Camera *camera; Transform cam_xform; SceneTree *tree = SceneTree::get_singleton(); List traffic_vehicles; List::Element *e; tree->get_nodes_in_group("traffic_vehicle", &traffic_vehicles); view = tree->get_root(); camera = view->get_camera(); cam_xform = camera->get_global_transform(); for (e = traffic_vehicles.front(); e; e = e->next()) { Node *node = e->get(); Spatial *sp = Object::cast_to(node); Transform xform = sp->get_global_transform(); Vector3 check = cam_xform.xform_inv(xform.origin); /* TODO: use AABB instead */ if (fabsf(check.x) > delete_distance.x || check.z > delete_distance.z || check.z < delete_distance.y) sp->queue_delete(); else if (fabsf(check.x) > physics_distance.x + 1.0f || check.z > physics_distance.z + 1.0f || check.z < physics_distance.y - 1) { if (!sp->has_meta("space")) vehicle_disable_physics(sp); } else if (fabsf(check.x) < physics_distance.x - 1.0f || check.z < physics_distance.z - 1.0f || check.z > physics_distance.y + 1) { if (sp->has_meta("space")) vehicle_enable_physics(sp); } } } void Traffic::vehicle_enable_physics(Spatial *obj) { RigidBody *body = Object::cast_to(obj); if (!body) return; RID space = obj->get_meta("space"); PhysicsServer::get_singleton()->body_set_space(body->get_rid(), space); obj->remove_meta("space"); if (obj->has_meta("velocity")) { Vector3 velocity = obj->get_meta("velocity"); body->set_linear_velocity(velocity); } } void Traffic::vehicle_disable_physics(Spatial *obj) { RigidBody *body = Object::cast_to(obj); if (!body) return; RID space = PhysicsServer::get_singleton()->body_get_space(body->get_rid()); Vector3 velocity = body->get_linear_velocity(); obj->set_meta("space", space); obj->set_meta("velocity", velocity); PhysicsServer::get_singleton()->body_set_space(body->get_rid(), RID()); } static Traffic *g_traffic_data = NULL; Traffic *Traffic::get_singleton() { return g_traffic_data; } void Traffic::create_singleton() { g_traffic_data = memnew(Traffic); } void Traffic::destroy_singleton() { memdelete(g_traffic_data); g_traffic_data = NULL; }