#include #include #include #include "spawner.h" static Spawner *g_spawner_data = NULL; Spawner * Spawner::get_singleton() { return g_spawner_data; } void Spawner::create_singleton() { g_spawner_data = memnew(Spawner); } void Spawner::destroy_singleton() { memdelete(g_spawner_data); } void Spawner::_bind_methods() { ClassDB::bind_method(D_METHOD("add_scene", "name", "scene"), &Spawner::add_scene); ClassDB::bind_method(D_METHOD("remove_scene", "name"), &Spawner::remove_scene); ClassDB::bind_method(D_METHOD("place_scene", "name", "place"), &Spawner::place_scene); ClassDB::bind_method(D_METHOD("place_scene_relative", "name", "parent", "place"), &Spawner::place_scene_relative); ClassDB::bind_method(D_METHOD("update_view", "node", "distance"), &Spawner::update_view); } void Spawner::add_scene(const StringName &name, Ref scene) { lock.lock(); if (!scenes.has(name)) { scenes[name] = scene; positions[name] = PoolVector(); } lock.unlock(); } void Spawner::remove_scene(const StringName &name) { int i; lock.lock(); PoolVector pos = positions[name]; for (i = 0; i < pos.size(); i++) { if (!pos[i].active) continue; Object *po = ObjectDB::get_instance(pos[i].instance); if (po) { Node *pn = Object::cast_to(po); if (pn) pn->queue_delete(); } pos.write()[i].active = false; } positions.erase(name); scenes.erase(name); lock.unlock(); } void Spawner::place_scene(const StringName &name, const Transform &place) { lock.lock(); if (scenes.has(name)) { struct spawn_object obj; obj.xform = place; obj.active = false; obj.instance = -1; PoolVector pos = positions[name]; pos.resize(pos.size() + 1); pos.write()[pos.size() - 1] = obj; positions[name] = pos; force_update = true; } lock.unlock(); } void Spawner::place_scene_relative(const StringName &name, Node *parent, const Transform &place) { } void Spawner::update_view(Node *node, float distance) { if (!node) return; Viewport *view = node->get_viewport(); if (!view) return; Camera *cam = view->get_camera(); if (!cam) return; Transform cam_xform = cam->get_global_transform(); Vector3 org = cam_xform.origin; if (org.distance_squared_to(last_org) < 64.0f && !force_update) return; last_org = org; const String *key; lock.lock(); for (key = positions.next(NULL); key; key = positions.next(key)) { int i; PoolVector pos = positions[*key]; for (i = 0; i < pos.size(); i++) { if (!pos[i].active) { Transform x = pos[i].xform; Vector3 npos = x.origin; float d = org.distance_squared_to(x.origin); if (d < distance * distance) { Node *pn = scenes[*key]->instance(); if (pn) { Spatial *sp = Object::cast_to(pn); if (sp) { view->add_child(sp); sp->set_global_transform(x); pos.write()[i].instance = sp->get_instance_id(); pos.write()[i].active = true; } else memfree(pn); } } } else { Transform x = pos[i].xform; float d = org.distance_squared_to(x.origin); if (d > distance * distance + 600.0f) { Object *po = ObjectDB::get_instance(pos[i].instance); if (po) { Node *pn = Object::cast_to(po); if (pn) pn->queue_delete(); } pos.write()[i].active = false; } } } positions[*key] = pos; } force_update = false; lock.unlock(); }