From b318f5ef8df5ab3ea8ea8acb21cdf9037dcd91ef Mon Sep 17 00:00:00 2001 From: Segey Lapin Date: Mon, 1 Nov 2021 05:57:07 +0300 Subject: [PATCH] Added traffic --- modules/world/register_types.cpp | 6 + modules/world/road_grid.cpp | 5 + modules/world/road_grid.h | 26 +++ modules/world/roads.cpp | 6 + modules/world/roads.h | 27 +++ modules/world/spawner.cpp | 34 ++-- modules/world/traffic.cpp | 283 +++++++++++++++++++++++++++++++ modules/world/traffic.h | 45 +++++ 8 files changed, 417 insertions(+), 15 deletions(-) create mode 100644 modules/world/traffic.cpp create mode 100644 modules/world/traffic.h diff --git a/modules/world/register_types.cpp b/modules/world/register_types.cpp index 10f4bc9..d9e9c5f 100644 --- a/modules/world/register_types.cpp +++ b/modules/world/register_types.cpp @@ -11,6 +11,7 @@ #include "road_grid.h" #include "roads.h" #include "spawner.h" +#include "traffic.h" void register_world_types() { @@ -22,6 +23,8 @@ void register_world_types() Engine::get_singleton()->add_singleton(Engine::Singleton("RoadsData", RoadsData::get_singleton())); Spawner::create_singleton(); Engine::get_singleton()->add_singleton(Engine::Singleton("Spawner", Spawner::get_singleton())); + Traffic::create_singleton(); + Engine::get_singleton()->add_singleton(Engine::Singleton("Traffic", Traffic::get_singleton())); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); @@ -35,6 +38,9 @@ void register_world_types() void unregister_world_types() { + RoadsData::destroy_singleton(); + Spawner::destroy_singleton(); + Traffic::destroy_singleton(); WorldMapData::destroy_singleton(); } diff --git a/modules/world/road_grid.cpp b/modules/world/road_grid.cpp index c21b648..c8f9ff9 100644 --- a/modules/world/road_grid.cpp +++ b/modules/world/road_grid.cpp @@ -14,6 +14,7 @@ RoadGrid::RoadGrid() { grid_width = 16; grid_height = 16; + astar.instance(); } RoadGrid::~RoadGrid() @@ -336,6 +337,10 @@ void RoadGrid::build(Ref curve, Ref noise) } map_sites.write[i].avg_height = min_height * 0.7f + max_height * 0.3f; } + for (i = 0; i < vertices.size(); i++) + astar->add_point(i, vertices[i], 20.0f); + for (i = 0; i < map_hedges.size(); i++) + astar->connect_points(map_hedges[i]->a, map_hedges[i]->b, false); generate_building_positions(); printf("building 3rd dimention done\n"); } diff --git a/modules/world/road_grid.h b/modules/world/road_grid.h index 16a4e02..c0ab865 100644 --- a/modules/world/road_grid.h +++ b/modules/world/road_grid.h @@ -6,6 +6,7 @@ #include #include #include +#include #include class CanvasItem; @@ -144,6 +145,7 @@ class RoadGrid: public Reference { GDCLASS(RoadGrid, Object) protected: Ref rnd; + Ref astar; int keep_seed; List clusters; Rect2 bounds; @@ -369,5 +371,29 @@ public: } PoolVector get_site_border(int site, float offt); PoolVector get_site_radial_points(int site, float bofft, float offt); + Ref get_astar() const + { + return astar; + } + inline int get_closest_point(Vector3 to_position, bool include_disabled=false) const + { + return astar->get_closest_point(to_position, include_disabled); + } + inline Vector3 get_closest_position_in_segment(Vector3 to_position) const + { + return astar->get_closest_position_in_segment(to_position); + } + inline PoolVector get_point_path(int p_from_id, int p_to_id) + { + return astar->get_point_path(p_from_id, p_to_id); + } + inline PoolVector get_id_path(int p_from_id, int p_to_id) + { + return astar->get_id_path(p_from_id, p_to_id); + } + inline Vector3 get_point_position(int p_id) const + { + return astar->get_point_position(p_id); + } }; #endif diff --git a/modules/world/roads.cpp b/modules/world/roads.cpp index 2d23da3..745fd70 100644 --- a/modules/world/roads.cpp +++ b/modules/world/roads.cpp @@ -574,6 +574,12 @@ void RoadsData::_bind_methods() ClassDB::bind_method(D_METHOD("get_site_type", "site"), &RoadsData::get_site_type); ClassDB::bind_method(D_METHOD("get_site_border", "site", "offt"), &RoadsData::get_site_border); ClassDB::bind_method(D_METHOD("get_site_radial_points", "site", "bofft", "offt"), &RoadsData::get_site_radial_points); + ClassDB::bind_method(D_METHOD("get_closest_point", "to_position"), &RoadsData::get_closest_point); + ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &RoadsData::get_closest_position_in_segment); + ClassDB::bind_method(D_METHOD("get_point_path", "p_from_id", "p_to_id"), &RoadsData::get_point_path); + ClassDB::bind_method(D_METHOD("get_id_path", "p_from_id", "p_to_id"), &RoadsData::get_id_path); + ClassDB::bind_method(D_METHOD("get_point_position", "p_id"), &RoadsData::get_point_position); + } void RoadsData::set_noise(Ref noise) { diff --git a/modules/world/roads.h b/modules/world/roads.h index 79dbf26..0039ec2 100644 --- a/modules/world/roads.h +++ b/modules/world/roads.h @@ -1,3 +1,5 @@ +#ifndef ROADS_H +#define ROADS_H #include #include @@ -150,5 +152,30 @@ public: { return rg->get_site_radial_points(site, bofft, offt); } + inline Ref get_astar() const + { + return rg->get_astar(); + } + inline int get_closest_point(Vector3 to_position, bool include_disabled=false) const + { + return rg->get_closest_point(to_position, include_disabled); + } + inline Vector3 get_closest_position_in_segment(Vector3 to_position) const + { + return rg->get_closest_position_in_segment(to_position); + } + inline PoolVector get_point_path(int p_from_id, int p_to_id) + { + return rg->get_point_path(p_from_id, p_to_id); + } + inline PoolVector get_id_path(int p_from_id, int p_to_id) + { + return rg->get_id_path(p_from_id, p_to_id); + } + inline Vector3 get_point_position(int p_id) const + { + return rg->get_point_position(p_id); + } }; +#endif diff --git a/modules/world/spawner.cpp b/modules/world/spawner.cpp index 2d1fd5e..cb5490e 100644 --- a/modules/world/spawner.cpp +++ b/modules/world/spawner.cpp @@ -104,34 +104,38 @@ void Spawner::update_view(Node *node, float distance) int i; PoolVector pos = positions[*key]; for (i = 0; i < pos.size(); i++) { - if (!pos[i].active) { + if (!pos[i].active && !pos[i].pooled) { Transform x = pos[i].xform; float d = org.distance_squared_to(x.origin); if (d < distance * distance && pos[i].instance < 0) { int j; Node *pn = NULL; bool pooling = false; - for (j = 0; j < pos.size(); j++) { - if (j == i) - continue; - if (!pos[j].active && pos[j].instance >= 0 && pos[j].pooled) { - pos.write()[i].instance = pos[j].instance; - pos.write()[j].instance = -1; - pos.write()[j].pooled = false; - Object *po = ObjectDB::get_instance(pos[i].instance); - if (po) { - pn = Object::cast_to(po); - if (pn) { - pooling = true; - break; + if (pos.size() > 4) { + for (j = 0; j < pos.size(); j++) { + if (j == i) + continue; + if (!pos[j].active && pos[j].instance >= 0 && pos[j].pooled) { + pos.write()[i].instance = pos[j].instance; + pos.write()[j].instance = -1; + pos.write()[j].pooled = false; + Object *po = ObjectDB::get_instance(pos[i].instance); + if (po) { + pn = Object::cast_to(po); + if (pn) { + pooling = true; + break; + } } } } } if (!pn) pn = scenes[*key]->instance(); + assert(pn); if (pn) { Spatial *sp = Object::cast_to(pn); + assert(sp); if (sp) { if (!pooling) view->add_child(sp); @@ -144,7 +148,7 @@ void Spawner::update_view(Node *node, float distance) memfree(pn); } } - } else { + } else if (pos[i].active) { Transform x = pos[i].xform; float d = org.distance_squared_to(x.origin); if (d > distance * distance + 2500.0f) { diff --git a/modules/world/traffic.cpp b/modules/world/traffic.cpp new file mode 100644 index 0000000..c70111c --- /dev/null +++ b/modules/world/traffic.cpp @@ -0,0 +1,283 @@ +#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)), + 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); + if (fabsf(check.x) > delete_distance.x || + check.z > delete_distance.z || + check.z < delete_distance.y) + sp->queue_delete(); + } +} + +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; +} + diff --git a/modules/world/traffic.h b/modules/world/traffic.h new file mode 100644 index 0000000..b1f357a --- /dev/null +++ b/modules/world/traffic.h @@ -0,0 +1,45 @@ +#include +class Traffic: public Object { + GDCLASS(Traffic, Object); +protected: + static void _bind_methods(); + Vector > scenes; + int state; + List spawner_list; + List::Element *spawner_e; + float max_spawn_distance; + float min_spawn_distance; + Vector3 delete_distance; + Ref rnd; + float list_cooldown, spawn_cooldown; + RID immediate, instance; + Ref debug_mat; + bool debug; + + void debug_traffic(); + void control_traffic(); +public: + Traffic(); + ~Traffic(); + void add_traffic_vehicle(Ref scene); + void remove_traffic_vehicle(Ref scene); + void idle_runner(); + + inline void set_seed(int seed) + { + rnd->set_seed(seed); + } + inline int get_state() + { + return rnd->get_state(); + } + inline void set_state(int seed) + { + rnd->set_state(seed); + } + + static Traffic *get_singleton(); + static void create_singleton(); + static void destroy_singleton(); +}; +