Spawner for scenes
This commit is contained in:
163
modules/world/spawner.cpp
Normal file
163
modules/world/spawner.cpp
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <scene/main/viewport.h>
|
||||||
|
#include <scene/3d/camera.h>
|
||||||
|
#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<PackedScene> scene)
|
||||||
|
{
|
||||||
|
lock.lock();
|
||||||
|
if (!scenes.has(name)) {
|
||||||
|
scenes[name] = scene;
|
||||||
|
positions[name] = PoolVector<struct spawn_object>();
|
||||||
|
}
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
void Spawner::remove_scene(const StringName &name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
lock.lock();
|
||||||
|
PoolVector<struct spawn_object> 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<Node>(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.relative = false;
|
||||||
|
obj.instance = -1;
|
||||||
|
PoolVector<struct spawn_object> 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)
|
||||||
|
{
|
||||||
|
lock.lock();
|
||||||
|
if (scenes.has(name)) {
|
||||||
|
struct spawn_object obj;
|
||||||
|
obj.xform = place;
|
||||||
|
obj.active = false;
|
||||||
|
obj.relative = true;
|
||||||
|
obj.instance = -1;
|
||||||
|
obj.parent_instance = parent->get_instance_id();
|
||||||
|
PoolVector<struct spawn_object> pos = positions[name];
|
||||||
|
pos.resize(pos.size() + 1);
|
||||||
|
pos.write()[pos.size() - 1] = obj;
|
||||||
|
positions[name] = pos;
|
||||||
|
force_update = true;
|
||||||
|
}
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
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<struct spawn_object> pos = positions[*key];
|
||||||
|
for (i = 0; i < pos.size(); i++) {
|
||||||
|
Spatial *pnode = NULL;
|
||||||
|
if (pos[i].relative) {
|
||||||
|
Object *p = ObjectDB::get_instance(pos[i].parent_instance);
|
||||||
|
pnode = Object::cast_to<Spatial>(p);
|
||||||
|
assert(pnode);
|
||||||
|
}
|
||||||
|
if (!pos[i].active) {
|
||||||
|
Transform x = pos[i].xform;
|
||||||
|
Vector3 npos = x.origin;
|
||||||
|
if (pnode)
|
||||||
|
npos = pnode->get_global_transform().xform(npos);
|
||||||
|
float d = org.distance_squared_to(x.origin);
|
||||||
|
if (d < distance * distance) {
|
||||||
|
Node *pn = scenes[*key]->instance();
|
||||||
|
if (pn) {
|
||||||
|
Spatial *sp = Object::cast_to<Spatial>(pn);
|
||||||
|
if (sp) {
|
||||||
|
if (pnode) {
|
||||||
|
pnode->add_child(sp);
|
||||||
|
sp->set_transform(x);
|
||||||
|
} else {
|
||||||
|
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<Node>(po);
|
||||||
|
if (pn)
|
||||||
|
pn->queue_delete();
|
||||||
|
}
|
||||||
|
pos.write()[i].active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
positions[*key] = pos;
|
||||||
|
}
|
||||||
|
force_update = false;
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
29
modules/world/spawner.h
Normal file
29
modules/world/spawner.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include <scene/main/node.h>
|
||||||
|
#include <scene/resources/packed_scene.h>
|
||||||
|
class Spawner: public Object {
|
||||||
|
GDCLASS(Spawner, Object);
|
||||||
|
protected:
|
||||||
|
Vector3 last_org;
|
||||||
|
bool force_update;
|
||||||
|
HashMap<String, Ref<PackedScene> > scenes;
|
||||||
|
struct spawn_object {
|
||||||
|
Transform xform;
|
||||||
|
bool active;
|
||||||
|
bool relative;
|
||||||
|
int parent_instance;
|
||||||
|
int instance;
|
||||||
|
};
|
||||||
|
HashMap<String, PoolVector<struct spawn_object> > positions;
|
||||||
|
Mutex lock;
|
||||||
|
static void _bind_methods();
|
||||||
|
public:
|
||||||
|
void add_scene(const StringName &name, Ref<PackedScene> scene);
|
||||||
|
void remove_scene(const StringName &name);
|
||||||
|
void place_scene(const StringName &name, const Transform &place);
|
||||||
|
void place_scene_relative(const StringName &name, Node *parent, const Transform &place);
|
||||||
|
void update_view(Node *node, float distance);
|
||||||
|
static void create_singleton();
|
||||||
|
static void destroy_singleton();
|
||||||
|
static Spawner *get_singleton();
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user