1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 15:02:34 +02:00

Implement Game Object ID allocation

This commit is contained in:
Daniel Evans 2015-04-29 21:03:53 +01:00
parent 25f62a0a47
commit 5d3ac6218e
15 changed files with 107 additions and 44 deletions

View File

@ -15,6 +15,7 @@ class GameState;
class CutsceneObject;
class WorkContext;
#include <objects/ObjectTypes.hpp>
class GameObject;
class CharacterObject;
@ -95,7 +96,12 @@ public:
* Creates a pedestrian.
*/
CharacterObject* createPedestrian(const uint16_t id, const glm::vec3& pos, const glm::quat& rot = glm::quat());
/**
* Inserts the given game object into the world.
*/
void insertObject(GameObject* object);
/**
* Destroys an existing Object
*/
@ -159,11 +165,9 @@ public:
SoundManager sound;
/**
* @brief objects All active GameObjects in the world.
* @todo add some mechanism to allow objects to be "locked" preventing deletion.
* @todo add deletion queue to allow objects to self delete.
* The active GameObjects within the world, mapped to their allocated ID
*/
std::set<GameObject*> objects;
std::map<GameObjectID, GameObject*> objects;
std::set<GameObject*> characters;

View File

@ -3,6 +3,7 @@
#define _GAMEOBJECT_HPP_
#include <engine/RWTypes.hpp>
#include <objects/ObjectTypes.hpp>
#include <loaders/LoaderIDE.hpp>
#include <loaders/LoaderIPL.hpp>
#include <render/Model.hpp>
@ -27,7 +28,7 @@ class GameObject
{
glm::vec3 _lastPosition;
glm::quat _lastRotation;
GameObjectID objectID;
public:
glm::vec3 position;
glm::quat rotation;
@ -58,7 +59,7 @@ public:
bool visible;
GameObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelRef model)
: _lastPosition(pos), _lastRotation(rot), position(pos), rotation(rot),
: _lastPosition(pos), _lastRotation(rot), objectID(-1), position(pos), rotation(rot),
model(model), engine(engine), animator(nullptr), skeleton(nullptr), mHealth(0.f),
inWater(false), _lastHeight(std::numeric_limits<float>::max()), visible(true),
lifetime(GameObject::UnknownLifetime)
@ -66,6 +67,12 @@ public:
virtual ~GameObject();
GameObjectID getGameObjectID() const { return objectID; }
/**
* Do not call this, use GameWorld::insertObject
*/
void setGameObjectID(GameObjectID id) { objectID = id; }
/**
* @brief Enumeration of possible object types.
*/

View File

@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
/**
* all wordly GameObjects are associated with a 32-bit identifier
*/
typedef uint32_t GameObjectID;

View File

@ -47,7 +47,8 @@ void PlayerController::enterNearestVehicle()
auto world = character->engine;
VehicleObject* nearest = nullptr; float d = 10.f;
for( GameObject* object : world->objects ) {
for( auto& p : world->objects ) {
auto object = p.second;
if( object->type() == GameObject::Vehicle ) {
float vd = glm::length( character->getPosition() - object->getPosition());
if( vd < d ) {

View File

@ -95,8 +95,8 @@ GameWorld::GameWorld(Logger* log, WorkContext* work, GameData* dat)
GameWorld::~GameWorld()
{
for(auto o : objects) {
delete o;
for(auto& p : objects) {
delete p.second;
}
delete dynamicsWorld;
@ -126,7 +126,8 @@ bool GameWorld::placeItems(const std::string& name)
}
// Attempt to Associate LODs.
for(GameObject* object : objects) {
for(auto& p: objects) {
auto object = p.second;
if( object->type() == GameObject::Instance ) {
InstanceObject* instance = static_cast<InstanceObject*>(object);
if( !instance->object->LOD ) {
@ -192,7 +193,7 @@ InstanceObject *GameWorld::createInstance(const uint16_t id, const glm::vec3& po
oi, nullptr, dydata
);
objects.insert(instance);
insertObject(instance);
if( shouldBeOnGrid(instance) )
{
@ -219,16 +220,16 @@ void GameWorld::createTraffic(const glm::vec3& near)
void GameWorld::cleanupTraffic(const glm::vec3& focus)
{
for ( GameObject* object : objects )
for ( auto& p : objects )
{
if ( object->getLifetime() != GameObject::TrafficLifetime )
if ( p.second->getLifetime() != GameObject::TrafficLifetime )
{
continue;
}
if ( glm::distance( focus, object->getPosition() ) >= 100.f )
if ( glm::distance( focus, p.second->getPosition() ) >= 100.f )
{
destroyObjectQueued( object );
destroyObjectQueued( p.second );
}
}
destroyQueuedObjects();
@ -301,7 +302,7 @@ CutsceneObject *GameWorld::createCutsceneObject(const uint16_t id, const glm::ve
pos,
m);
objects.insert(instance);
insertObject( instance );
return instance;
@ -365,7 +366,7 @@ VehicleObject *GameWorld::createVehicle(const uint16_t id, const glm::vec3& pos,
auto vehicle = new VehicleObject{ this, pos, rot, m, vti, info->second, prim, sec };
objects.insert(vehicle);
insertObject( vehicle );
return vehicle;
}
@ -404,7 +405,7 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3
if(m && m->resource) {
auto ped = new CharacterObject( this, pos, rot, m, pt );
objects.insert(ped);
insertObject(ped);
characters.insert(ped);
new DefaultAIController(ped);
return ped;
@ -413,6 +414,19 @@ CharacterObject* GameWorld::createPedestrian(const uint16_t id, const glm::vec3
return nullptr;
}
void GameWorld::insertObject(GameObject* object)
{
// Find the lowest free GameObjectID.
GameObjectID availID = 1;
for( auto& p : objects )
{
if( p.first == availID ) availID++;
}
object->setGameObjectID( availID );
objects[availID] = object;
}
void GameWorld::destroyObject(GameObject* object)
{
auto coord = worldToGrid(glm::vec2(object->getPosition()));
@ -423,7 +437,7 @@ void GameWorld::destroyObject(GameObject* object)
auto index = (coord.x * WORLD_GRID_WIDTH) + coord.y;
worldGrid[index].instances.erase(object);
auto iterator = objects.find(object);
auto iterator = objects.find(object->getGameObjectID());
if( iterator != objects.end() ) {
delete object;
objects.erase(iterator);
@ -653,7 +667,8 @@ void GameWorld::PhysicsTickCallback(btDynamicsWorld *physWorld, btScalar timeSte
{
GameWorld* world = static_cast<GameWorld*>(physWorld->getWorldUserInfo());
for( GameObject* object : world->objects ) {
for( auto& p : world->objects ) {
GameObject* object = p.second;
if( object->type() == GameObject::Vehicle ) {
static_cast<VehicleObject*>(object)->tickPhysics(timeStep);
}
@ -708,7 +723,8 @@ void GameWorld::startCutscene()
void GameWorld::clearCutscene()
{
for(auto o : objects) {
for(auto& p : objects) {
auto o = p.second;
if( o->type() == GameObject::Cutscene ) {
destroyObjectQueued(o);
}

View File

@ -121,7 +121,7 @@ void WeaponItem::fireProjectile()
_wepData
});
_character->engine->objects.insert( projectile );
_character->engine->insertObject( projectile );
}
void WeaponItem::primary(bool active)

View File

@ -49,7 +49,8 @@ void ProjectileObject::explode()
const float damage = _info.weapon->damage;
/// @todo accelerate this with bullet instead of doing this stupid loop.
for(auto& o : engine->objects) {
for(auto& p : engine->objects) {
auto o = p.second;
if( o == this ) continue;
switch( o->type() ) {
case GameObject::Instance:

View File

@ -297,7 +297,8 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera &camera, float
renderer->pushDebugGroup("Objects");
renderer->pushDebugGroup("Dynamic");
for( GameObject* object : world->objects ) {
for( auto& p : world->objects ) {
auto object = p.second;
if(! object->visible )
{
continue;

View File

@ -99,9 +99,9 @@ void game_create_character(const ScriptArguments& args)
it != args.getWorld()->objects.end();
++it)
{
if( (*it)->type() == GameObject::Character && glm::distance(position, (*it)->getPosition()) < replaceThreshold )
if( it->second->type() == GameObject::Character && glm::distance(position, it->second->getPosition()) < replaceThreshold )
{
args.getWorld()->destroyObjectQueued(*it);
args.getWorld()->destroyObjectQueued(it->second);
}
}
@ -139,9 +139,9 @@ void game_create_vehicle(const ScriptArguments& args)
it != args.getWorld()->objects.end();
++it)
{
if( (*it)->type() == GameObject::Vehicle && glm::distance(position, (*it)->getPosition()) < replaceThreshold )
if( it->second->type() == GameObject::Vehicle && glm::distance(position, it->second->getPosition()) < replaceThreshold )
{
args.getWorld()->destroyObjectQueued(*it);
args.getWorld()->destroyObjectQueued(it->second);
}
}
@ -538,8 +538,9 @@ bool game_objects_in_volume(const ScriptArguments& args)
bool objects = args[9].integer;
bool particles = args[10].integer;
for(GameObject* object : args.getWorld()->objects)
for(auto& pair : args.getWorld()->objects)
{
GameObject* object = pair.second;
switch( object->type() )
{
case GameObject::Instance:
@ -682,7 +683,7 @@ void game_create_pickup(const ScriptArguments& args)
auto pickup = new GenericPickup(args.getWorld(), pos, id, type);
args.getWorld()->objects.insert(pickup);
args.getWorld()->insertObject( pickup );
*args[5].handle = pickup;
}
@ -842,7 +843,8 @@ void game_set_close_object_visible(const ScriptArguments& args)
std::transform(model.begin(), model.end(), model.begin(), ::tolower);
for(auto o : args.getWorld()->objects) {
for(auto& p : args.getWorld()->objects) {
auto o = p.second;
if( o->type() == GameObject::Instance ) {
if( !o->model ) continue;
if( o->model->name != model ) continue;
@ -899,7 +901,8 @@ void game_change_nearest_model(const ScriptArguments& args)
auto nobj = args.getWorld()->data->findObjectType<ObjectData>(newobjectid);
/// @todo Objects need to adopt the new object ID, not just the model.
for(auto o : args.getWorld()->objects) {
for(auto p : args.getWorld()->objects) {
auto o = p.second;
if( o->type() == GameObject::Instance ) {
if( !o->model ) continue;
if( o->model->name != oldmodel ) continue;

View File

@ -0,0 +1,19 @@
#include <boost/test/unit_test.hpp>
#include <engine/GameWorld.hpp>
#include <engine/GameData.hpp>
#include <test_globals.hpp>
BOOST_AUTO_TEST_SUITE(GameWorldTests)
BOOST_AUTO_TEST_CASE(test_gameobject_id)
{
GameData gd(&Global::get().log, &Global::get().work, Global::getGamePath());
GameWorld gw(&Global::get().log, &Global::get().work, &gd);
auto object1 = gw.createInstance(1337, glm::vec3(100.f, 0.f, 0.f));
auto object2 = gw.createInstance(1337, glm::vec3(100.f, 0.f, 0.f));
BOOST_CHECK_NE( object1->getObjectID(), object2->getObjectID() );
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -314,7 +314,8 @@ void RWGame::tick(float dt)
}
}
for( GameObject* object : world->objects ) {
for( auto& p : world->objects ) {
GameObject* object = p.second;
object->_updateLastTransform();
object->tick(dt);
}
@ -502,8 +503,9 @@ void RWGame::renderDebugStats(float time, Renderer::ProfileInfo& worldRenderTime
// Count the number of interesting objects.
int peds = 0, cars = 0;
for( GameObject* object : world->objects )
for( auto& p : world->objects )
{
GameObject* object = p.second;
switch ( object->type() )
{
case GameObject::Character: peds++; break;

View File

@ -36,7 +36,7 @@ void IngameState::startTest()
glm::vec3 itemspawn( 276.5f, -609.f, 36.5f);
for( auto& w : getWorld()->data->weaponData ) {
if( w.first == "unarmed" ) continue;
getWorld()->objects.insert(new ItemPickup(getWorld(), itemspawn,
getWorld()->insertObject(new ItemPickup(getWorld(), itemspawn,
w.second));
itemspawn.x += 2.5f;
}

View File

@ -8,18 +8,19 @@ BOOST_AUTO_TEST_SUITE(LifetimeTests)
BOOST_AUTO_TEST_CASE(test_cleanup)
{
GameObject* f = Global::get().e->createInstance(1337, glm::vec3(0.f, 0.f, 1000.f));
auto id = f->getGameObjectID();
f->setLifetime(GameObject::TrafficLifetime);
{
auto search = Global::get().e->objects.find( f );
auto search = Global::get().e->objects.find( id );
BOOST_CHECK( search != Global::get().e->objects.end() );
}
Global::get().e->cleanupTraffic(glm::vec3(0.f, 0.f, 0.f));
{
auto search = Global::get().e->objects.find( f );
auto search = Global::get().e->objects.find( id );
BOOST_CHECK( search == Global::get().e->objects.end() );
}
}

View File

@ -31,7 +31,7 @@ BOOST_AUTO_TEST_CASE(test_pickup_interaction)
TestPickup* p = new TestPickup(Global::get().e, { 30.f, 0.f, 0.f } );
Global::get().e->objects.insert(p);
Global::get().e->insertObject(p);
BOOST_CHECK( ! p->picked_up );
@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(test_item_pickup)
ItemPickup* p = new ItemPickup(Global::get().e, { 30.f, 0.f, 0.f }, item );
Global::get().e->objects.insert(p);
Global::get().e->insertObject(p);
// Check the characters inventory is empty.
BOOST_CHECK( character->getInventory().empty() );

View File

@ -42,7 +42,7 @@ BOOST_AUTO_TEST_CASE(TestProjectile)
wepdata
});
Global::get().e->objects.insert( projectile );
Global::get().e->insertObject( projectile );
BOOST_CHECK( character->mHealth == 100.f );
@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(TestProjectile)
wepdata
});
Global::get().e->objects.insert( projectile );
Global::get().e->insertObject( projectile );
BOOST_CHECK( character->mHealth == 100.f );
@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(TestProjectile)
wepdata
});
Global::get().e->objects.insert( projectile );
Global::get().e->insertObject( projectile );
BOOST_CHECK( character->mHealth == 100.f );