1.ComponentsCommon.h
#pragma once
#include "..\Common\CommonHeaders.h"
#include "..\Common\Id.h"
#include "..\EngineAPI\GameEntity.h"
/*
namespace primal::game_entity
{
DEFINE_TYPED_ID(entity_id);
}
*/
2.Entity.cpp
#include "Entity.h"
#include "Script.h"
#include "Transform.h"
namespace primal::game_entity {
namespace {
utl::vector<transform::component> transforms;
utl::vector<script::component> scripts;
utl::vector<id::generation_type> generations;
utl::deque<entity_id> free_ids;
}
entity
create(const entity_info info)
{
assert(info.transform);
if (!info.transform) return entity{};
entity_id id;
if (free_ids.size() > id::min_deleted_elements)
{
id = free_ids.front();
assert(!is_alive( id ));
free_ids.pop_front();
id = entity_id{ id::new_generation(id) };
++generations[id::index(id)];
}
else
{
id = entity_id{ (id::id_type)generations.size() };
//transforms.resize(generations.size());
generations.push_back(0);
transforms.emplace_back();
scripts.emplace_back();
}
const entity new_entity{ id };
const id::id_type index{ id::index(id) };
//Create transform component
assert(!transforms[index].is_valid());
transforms[index] = transform::create(*info.transform, new_entity);
if (!transforms[index].is_valid()) return {};
//Create script component
if (info.script && info.script->script_creator)
{
assert(!scripts[index].is_valid());
scripts[index] = script::create(*info.script, new_entity);
assert(scripts[index].is_valid());
}
return new_entity;
}
void
remove(entity_id id)
{
//const entity_id id{ e.get_id() };
const id::id_type index{ id::index(id) };
assert(is_alive(id));
if(scripts[index].is_valid())
{
script::remove(scripts[index]);
scripts[index] = {};
}
transform::remove(transforms[index]);
transforms[index] = {};
free_ids.push_back(id);
}
bool is_alive(entity_id id)
{
assert(id::is_valid(id));
const id::id_type index{ id::index(id) };
assert(index < generations.size());
assert(generations[index] == id::generation(id));
return (generations[index] == id::generation(id) && transforms[index].is_valid());
}
transform::component
entity::transform() const
{
assert(is_alive(_id));
const id::id_type index{ id::index(_id) };
return transforms[index];
}
script::component
entity::script() const
{
assert(is_alive(_id));
const id::id_type index{ id::index(_id) };
return scripts[index];
}
}
3.Entity.h
#pragma once
#include "ComponentsCommon.h"
namespace primal
{
#define INIT_INFO(component) namespace component {struct init_info;}
INIT_INFO(transform);
INIT_INFO(script);
#undef INIT_INFO
namespace game_entity {
struct entity_info
{
transform::init_info* transform{ nullptr };
script::init_info* script{ nullptr };
};
entity create(const entity_info info);
void remove(entity_id id);
bool is_alive(entity_id id);
}
}
4.Script.cpp
#include "Script.h"
#include "Entity.h"
namespace primal::script {
namespace {
utl::vector<detail::script_ptr> entity_scripts;
utl::vector<id::id_type> id_mapping;
utl::vector<id::generation_type> generations;
utl::deque<script_id> free_ids;
using script_registry = std::unordered_map<size_t, detail::script_creator>;
script_registry&
registery()
{
static script_registry reg;
return reg;
}
#ifdef USE_WITH_EDITOR
utl::vector<std::string>&
scripts_name()
{
static utl::vector<std::string> names;
return names;
}
#endif
bool
exists(script_id id)
{
assert(id::is_valid(id));
const id::id_type index{ id::index(id) };
assert(index < generations.size() && id_mapping[index] < entity_scripts.size());
assert(generations[index] == id::generation(id));
return (generations[index] == id::generation(id)) &&
entity_scripts[id_mapping[index]] &&
entity_scripts[id_mapping[index]]->is_valid();
}
}
namespace detail
{
u8 register_script(size_t tag, script_creator func)
{
bool result{ registery().insert(script_registry::value_type{tag,func}).second };
assert(result);
return result;
}
script_creator
get_script_creator(size_t tag)
{
auto script = primal::script::registery().find(tag);
assert(script != primal::script::registery().end() && script->first == tag);
return script->second;
}
#ifdef USE_WITH_EDITOR
u8
add_script_name(const char* name)
{
script_names().emplace_back(name);
return true;
}
#endif
}
component
create(init_info info, game_entity::entity entity){
assert(entity.is_valid());
assert(info.script_creator);
script_id id{};
if (free_ids.size() > id::min_deleted_elements)
{
id = free_ids.front();
assert(!exists(id));
free_ids.pop_front();
id = script_id{ id::new_generation(id) };
++generations[id::index(id)];
}
else
{
id = script_id{ (id::id_type)id_mapping.size() };
id_mapping.emplace_back();
generations.push_back(0);
}
assert(id::is_valid(id));
const id::id_type index{ (id::id_type)entity_scripts.size()};
entity_scripts.emplace_back(info.script_creator(entity));
assert(entity_scripts.back()->get_id() == entity.get_id());
id_mapping[id::index(id)] = index;
return component{id};
}
void remove(component c)
{
assert(c.is_valid() && exists(c.get_id()));
const script_id id{ c.get_id() };
const id::id_type index{ id_mapping[id::index(id)] };
const script_id last_id{ entity_scripts.back()->script().get_id() };
utl::erase_unordered(entity_scripts, index);
id_mapping[id::index(last_id)] = index;
id_mapping[id::index(id)] = id::invalid_id;
}
void update(float dt)
{
for (auto& ptr : entity_scripts)
{
ptr->update(dt);
}
}
}
#ifdef USE_WITH_EDITOR
#include <atlsafe.h>
extern "C" __declspec(dllexport)
LPSAFEARRY
get_script_names()
{
const u32 size{ (u32)primal::script::script_names().size() };
if (!size) return nullptr;
CComSafeArray<BSTR> names(size);
for (u32 i{ 0 }; i < size; ++i)
{
names.SetAt(i, A2BSTR_EX(primal::script::script_names()[i].c_str()),false);
}
return names.Detach();
}
#endif
总引擎核心运行成功的代码截图