00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "gameobject.h"
00022 #include "gameobjectprivate.h"
00023 #include "component.h"
00024 #include "core/debughelper.h"
00025 #include "game.h"
00026 #include "scene.h"
00027
00028 REGISTER_OBJECTTYPE( GluonEngine, GameObject )
00029
00030 using namespace GluonEngine;
00031
00032 GameObject::GameObject( QObject* parent )
00033 : GluonObject( parent )
00034 , d( new GameObjectPrivate )
00035 {
00036 updateTransform();
00037 }
00038
00039 GameObject::GameObject( const GameObject& other, QObject* parent )
00040 : GluonObject( parent )
00041 , d( other.d )
00042 {
00043 updateTransform();
00044 }
00045
00046 GameObject::~GameObject()
00047 {
00048 delete d;
00049 }
00050
00051 void
00052 GameObject::sanitize()
00053 {
00054 if( parent() )
00055 {
00056 if( parent()->metaObject() )
00057 {
00058 if( QString::compare( parent()->metaObject()->className(), "GameObject" ) )
00059 {
00060 GameObject* theParent = qobject_cast<GameObject*>( parent() );
00061 if( theParent )
00062 {
00063 theParent->addChild( this );
00064 }
00065 }
00066 }
00067 }
00068 GluonObject::sanitize();
00069 }
00070
00071 void
00072 GameObject::initialize()
00073 {
00074 const int componentCount = d->components.count();
00075 int i;
00076 for( i = 0; i < componentCount; ++i )
00077 if( d->components.at( i )->enabled() )
00078 d->components.at( i )->initialize();
00079
00080 const int childCount = d->children.count();
00081 for( i = 0; i < childCount; ++i )
00082 d->children.at( i )->initialize();
00083 }
00084
00085 void
00086 GameObject::start()
00087 {
00088 const int componentCount = d->components.count();
00089 int i;
00090 for( i = 0; i < componentCount; ++i )
00091 if( d->components.at( i )->enabled() )
00092 d->components.at( i )->start();
00093
00094 const int childCount = d->children.count();
00095 for( i = 0; i < childCount; ++i )
00096 d->children.at( i )->start();
00097 }
00098
00099 void
00100 GameObject::update( int elapsedMilliseconds )
00101 {
00102 if( !d->enabled )
00103 return;
00104
00105
00106 const int deleteCount = d->objectsToDelete.count();
00107 int i = 0;
00108
00109 for( i = 0; i < deleteCount; ++i )
00110 {
00111 GameObject* obj = d->objectsToDelete.at( i );
00112 removeChild( obj );
00113 obj->stop();
00114 obj->cleanup();
00115 delete obj;
00116 }
00117
00118 d->objectsToDelete.clear();
00119
00120
00121 const int componentCount = d->components.count();
00122 for( i = 0; i < componentCount; ++i )
00123 if( d->components.at( i )->enabled() )
00124 d->components.at( i )->update( elapsedMilliseconds );
00125
00126
00127 const int childCount = d->children.count();
00128 for( i = 0; i < childCount; ++i )
00129 d->children.at( i )->update( elapsedMilliseconds );
00130 }
00131
00132 void
00133 GameObject::draw( int timeLapse )
00134 {
00135 if( !d->enabled )
00136 return;
00137
00138 const int componentCount = d->components.count();
00139 int i;
00140 for( i = 0; i < componentCount; ++i )
00141 if( d->components.at( i )->enabled() )
00142 d->components.at( i )->draw( timeLapse );
00143
00144 const int childCount = d->children.count();
00145 for( i = 0; i < childCount; ++i )
00146 d->children.at( i )->draw( timeLapse );
00147 }
00148
00149 void GameObject::stop()
00150 {
00151 const int componentCount = d->components.count();
00152 int i;
00153 for( i = 0; i < componentCount; ++i )
00154 if( d->components.at( i )->enabled() )
00155 d->components.at( i )->stop();
00156
00157 const int childCount = d->children.count();
00158 for( i = 0; i < childCount; ++i )
00159 d->children.at( i )->stop();
00160 }
00161
00162 void
00163 GameObject::cleanup()
00164 {
00165 const int componentCount = d->components.count();
00166 int i;
00167 for( i = 0; i < componentCount; ++i )
00168 if( d->components.at( i )->enabled() )
00169 d->components.at( i )->cleanup();
00170
00171 const int childCount = d->children.count();
00172 for( i = 0; i < childCount; ++i )
00173 d->children.at( i )->cleanup();
00174 }
00175
00176 void GameObject::destroy()
00177 {
00178 parentGameObject()->removeLater( this );
00179 }
00180
00181 void GameObject::removeLater( GameObject* remove )
00182 {
00183 d->objectsToDelete.append( remove );
00184 }
00185
00186 void
00187 GameObject::runCommand( const QString& functionName )
00188 {
00189 #ifdef __GNUC__
00190 #warning TODO: Implement - QMetaObject::invokeMethod does lots of magic, and we really ought to support it all... postponing implementation for a little while until the rest is complete
00191 #endif
00192 }
00193
00194 void
00195 GameObject::runCommandInChildren( const QString& functionName )
00196 {
00197 foreach( GameObject * child, d->children )
00198 child->runCommand( functionName );
00199 }
00200
00201
00202
00203
00204 Component *
00205 GameObject::findComponent( const QString& name ) const
00206 {
00207 Component* found = 0;
00208
00209 foreach( Component * component, d->components )
00210 {
00211 if( component->name() == name )
00212 {
00213 found = component;
00214 break;
00215 }
00216 }
00217 return found;
00218 }
00219
00220 Component *
00221 GameObject::findComponentByType( const QString& typeName ) const
00222 {
00223 int typeID = QMetaType::type( typeName.toAscii().data() );
00224 return findComponentByType( typeID );
00225 }
00226
00227 Component*
00228 GameObject::findComponentByType( int type ) const
00229 {
00230 if( d->componentTypes.find( type ) != d->componentTypes.end() )
00231 return d->componentTypes.value( type );
00232
00233 return 0;
00234 }
00235
00236 QList<Component*>
00237 GameObject::findComponentsByType( const QString& typeName ) const
00238 {
00239 int typeID = QMetaType::type( typeName.toAscii().data() );
00240 return findComponentsByType( typeID );
00241 }
00242
00243 QList< Component* >
00244 GameObject::findComponentsByType( int type ) const
00245 {
00246 if( d->componentTypes.find( type ) != d->componentTypes.end() )
00247 return d->componentTypes.values( type );
00248
00249 return QList< Component* >();
00250 }
00251
00252 Component *
00253 GameObject::findComponentInChildren( const QString& name ) const
00254 {
00255 Component* found = 0;
00256 foreach( GameObject * child, d->children )
00257 {
00258 found = child->findComponent( name );
00259 if( found )
00260 break;
00261 found = child->findComponentInChildren( name );
00262 if( found )
00263 break;
00264 }
00265 return found;
00266 }
00267
00268 Component *
00269 GameObject::findComponentInChildrenByType( const QString& typeName ) const
00270 {
00271 Component* found = 0;
00272 foreach( GameObject * child, d->children )
00273 {
00274 found = child->findComponentByType( typeName );
00275 if( found )
00276 break;
00277 found = child->findComponentInChildrenByType( typeName );
00278 if( found )
00279 break;
00280 }
00281 return found;
00282 }
00283
00284 QList<Component*>
00285 GameObject::findComponentsInChildren( const QString& name ) const
00286 {
00287 QList<Component*> found;
00288 Component* tempFound;
00289 foreach( GameObject * child, d->children )
00290 {
00291 tempFound = child->findComponent( name );
00292 if( tempFound )
00293 found.append( tempFound );
00294 found.append( child->findComponentInChildren( name ) );
00295 }
00296 return found;
00297 }
00298
00299 QList<Component*>
00300 GameObject::findComponentsInChildrenByType( const QString& typeName ) const
00301 {
00302 QList<Component*> found;
00303 Component* tempFound;
00304 foreach( GameObject * child, d->children )
00305 {
00306 tempFound = child->findComponentByType( typeName );
00307 if( tempFound )
00308 found.append( tempFound );
00309 found.append( child->findComponentsInChildrenByType( typeName ) );
00310 }
00311 return found;
00312 }
00313
00314 QList< Component* >
00315 GameObject::findComponentsInChildrenByType( int type ) const
00316 {
00317 QList<Component*> found;
00318 foreach( GameObject * child, d->children )
00319 {
00320 found.append( child->findComponentsByType( type ) );
00321 found.append( child->findComponentsInChildrenByType( type ) );
00322 }
00323 return found;
00324 }
00325
00326 void
00327 GameObject::addComponent( Component* addThis )
00328 {
00329 if( addThis )
00330 {
00331 int typeID = QMetaType::type( addThis->metaObject()->className() );
00332 if( d->componentTypes.constFind( typeID, addThis ) == d->componentTypes.constEnd() )
00333 {
00334 d->componentTypes.insert( typeID, addThis );
00335 d->components.append( addThis );
00336 addThis->setParent( this );
00337 addThis->setGameObject( this );
00338 addThis->setName( addThis->name() );
00339 }
00340 }
00341 else
00342 {
00343 DEBUG_BLOCK
00344 DEBUG_TEXT( "Attempting to add a null component" );
00345 }
00346 }
00347
00348 bool
00349 GameObject::removeComponent( Component* removeThis )
00350 {
00351 int typeID = QMetaType::type( removeThis->metaObject()->className() );
00352 d->componentTypes.remove( typeID, removeThis );
00353 return d->components.removeOne( removeThis );
00354 }
00355
00356 QList< Component* >
00357 GameObject::components() const
00358 {
00359 return d->components;
00360 }
00361
00362
00363
00364
00365 Scene* GameObject::scene() const
00366 {
00367 Scene* foundScene = 0;
00368 GluonObject* gluonParent = qobject_cast<GluonObject*>( parent() );
00369 while( qobject_cast<GameObject*>( gluonParent ) )
00370 {
00371 if( qobject_cast<Scene*>( gluonParent->parent() ) )
00372 {
00373 foundScene = qobject_cast<Scene*>( gluonParent->parent() );
00374 break;
00375 }
00376 gluonParent = qobject_cast<GluonObject*>( gluonParent->parent() );
00377 }
00378 return foundScene;
00379 }
00380
00381 GameObject *
00382 GameObject::childGameObject( int index ) const
00383 {
00384 return d->children.at( index );
00385 }
00386
00387 GameObject *
00388 GameObject::childGameObject( const QString& name ) const
00389 {
00390 GameObject* found = 0;
00391 foreach( GameObject * child, d->children )
00392 {
00393 if( child->name() == name )
00394 {
00395 found = child;
00396 break;
00397 }
00398 }
00399 return found;
00400 }
00401
00402 void GameObject::addChild( GluonObject* child )
00403 {
00404 if( qobject_cast<GameObject*>( child ) )
00405 addChild( qobject_cast<GameObject*>( child ) );
00406 else
00407 GluonCore::GluonObject::addChild( child );
00408 }
00409
00410 void
00411 GameObject::addChild( GameObject* addThis )
00412 {
00413 if( !addThis )
00414 {
00415 DEBUG_BLOCK
00416 DEBUG_TEXT( QString( "Fail-add! you're trying to add a NULL GameObject" ) );
00417 }
00418 else if( !d->children.contains( addThis ) )
00419 {
00420 d->children.append( addThis );
00421
00422 if( addThis->d->parentGameObject )
00423 addThis->d->parentGameObject->removeChild( addThis );
00424
00425 addThis->d->parentGameObject = this;
00426 GluonCore::GluonObject::addChild( addThis );
00427 }
00428 }
00429
00430 void
00431 GameObject::addChildAt( GameObject* addThis, int index )
00432 {
00433 if( !addThis || index >= d->children.count() )
00434 {
00435 DEBUG_BLOCK
00436 DEBUG_TEXT( QString( "Fail-add! you're trying to add a NULL GameObject or specified an index that is out of range." ) );
00437 }
00438 else if( !d->children.contains( addThis ) )
00439 {
00440 d->children.insert( index, addThis );
00441
00442 if( addThis->d->parentGameObject )
00443 addThis->d->parentGameObject->removeChild( addThis );
00444
00445 addThis->d->parentGameObject = this;
00446 GluonCore::GluonObject::addChild( addThis );
00447 }
00448 }
00449
00450 bool
00451 GameObject::removeChild( GameObject* removeThis )
00452 {
00453 removeThis->d->parentGameObject = 0;
00454 return d->children.removeOne( removeThis );
00455 }
00456
00457 bool GameObject::removeChild( GluonObject* child )
00458 {
00459 return GluonObject::removeChild( child );
00460 }
00461
00462 int
00463 GameObject::childCount() const
00464 {
00465 return d->children.count();
00466 }
00467
00468 int
00469 GameObject::childIndex( GameObject* child ) const
00470 {
00471 return d->children.indexOf( child );
00472 }
00473
00474 void
00475 GameObject::setParentGameObject( GameObject* newParent )
00476 {
00477
00478 if( d->parentGameObject == newParent )
00479 return;
00480
00481
00482 if( d->parentGameObject )
00483 d->parentGameObject->removeChild( this );
00484
00485
00486 if( newParent )
00487 newParent->addChild( this );
00488
00489 d->parentGameObject = newParent;
00490 }
00491
00492 GameObject *
00493 GameObject::parentGameObject()
00494 {
00495 return d->parentGameObject;
00496 }
00497
00498
00499
00500
00501 void
00502 GameObject::setDescription( const QString& newDescription )
00503 {
00504 d->description = newDescription;
00505 }
00506
00507 QString
00508 GameObject::description() const
00509 {
00510 return d->description;
00511 }
00512
00513 bool
00514 GameObject::enabled() const
00515 {
00516 return d->enabled;
00517 }
00518
00519 void
00520 GameObject::setEnabled( bool newEnabled )
00521 {
00522 d->enabled = newEnabled;
00523 }
00524
00526
00527 QVector3D
00528 GameObject::position() const
00529 {
00530 return d->position;
00531 }
00532
00533 QVector3D
00534 GameObject::worldPosition() const
00535 {
00536 return d->worldPosition;
00537 }
00538
00539 void
00540 GameObject::setPosition( const QVector3D& newPosition )
00541 {
00542 d->position = newPosition;
00543
00544 d->transformInvalidated = true;
00545 updateTransform();
00546 }
00547
00548 void GameObject::setPosition( float x, float y, float z )
00549 {
00550 setPosition( QVector3D( x, y, z ) );
00551 }
00552
00553 void GameObject::setPosition( float x, float y )
00554 {
00555 setPosition( QVector3D( x, y, d->position.z() ) );
00556 }
00557
00558 void
00559 GameObject::translate( const QVector3D& translation, GameObject::TransformSpace ts )
00560 {
00561 if( ts == TS_LOCAL )
00562 {
00563 QVector3D trans = d->orientation.rotatedVector( translation );
00564 trans = trans * d->scale;
00565 setPosition( position() + trans );
00566 }
00567 else
00568 {
00569 #ifdef __GNUC__
00570 #warning This probably needs fixing to account for world scale/orientation
00571 #endif
00572 QVector3D trans = d->worldOrientation.rotatedVector( translation );
00573 trans = trans * d->worldScale;
00574 setPosition( position() + trans );
00575 }
00576 }
00577
00578 void
00579 GameObject::translate( float x, float y, float z, GameObject::TransformSpace ts )
00580 {
00581 translate( QVector3D( x, y, z ), ts );
00582 }
00583
00584 void
00585 GameObject::translate( float x, float y, GameObject::TransformSpace ts )
00586 {
00587 translate( QVector3D( x, y, 0 ), ts );
00588 }
00589
00591
00592 QVector3D
00593 GameObject::scale() const
00594 {
00595 return d->scale;
00596 }
00597
00598 QVector3D
00599 GameObject::worldScale() const
00600 {
00601 return d->worldScale;
00602 }
00603
00604 void
00605 GameObject::setScale( const QVector3D& newScale )
00606 {
00607 d->scale = newScale;
00608
00609 d->transformInvalidated = true;
00610 updateTransform();
00611 }
00612
00613 void GameObject::setScale( float x, float y, float z )
00614 {
00615 setScale( QVector3D( x, y, z ) );
00616 }
00617
00618 void GameObject::scaleRelative( QVector3D scaling, GameObject::TransformSpace ts )
00619 {
00620 if( ts == TS_LOCAL )
00621 {
00622 setScale( scale() + scaling );
00623 }
00624 else
00625 {
00626 setScale(( worldScale() + scaling ) - scale() );
00627 }
00628 }
00629
00630 void GameObject::scaleRelative( float x, float y, float z, GameObject::TransformSpace ts )
00631 {
00632 scaleRelative( QVector3D( x, y, z ), ts );
00633 }
00634
00636
00637 QQuaternion GameObject::orientation() const
00638 {
00639 return d->orientation;
00640 }
00641
00642 QQuaternion
00643 GameObject::worldOrientation() const
00644 {
00645 return d->worldOrientation;
00646 }
00647
00648 void GameObject::setOrientation( const QQuaternion& newOrientation )
00649 {
00650 d->orientation = newOrientation;
00651
00652 d->transformInvalidated = true;
00653 updateTransform();
00654 }
00655
00656 void GameObject::orient( QQuaternion rotation, GameObject::TransformSpace ts )
00657 {
00658 if( ts == TS_LOCAL )
00659 {
00660 setOrientation( orientation() * rotation );
00661 }
00662 else
00663 {
00664
00665 }
00666 }
00667
00668 void GameObject::rotate( float angle, const QVector3D& axis, GameObject::TransformSpace ts )
00669 {
00670 QQuaternion orientation = QQuaternion::fromAxisAndAngle( axis, angle );
00671 orient( orientation, ts );
00672 }
00673
00674 void GameObject::updateTransform()
00675
00676 {
00677 if( !d->transformInvalidated )
00678 return;
00679
00680 GameObject* parent = parentGameObject();
00681
00682 if( parent )
00683 {
00684
00685 d->worldPosition = parent->worldPosition() + parent->worldOrientation().rotatedVector( parent->worldScale() * d->position );
00686 d->worldOrientation = parent->worldOrientation() * d->orientation;
00687 d->worldScale = parent->worldScale() * d->scale;
00688 }
00689 else
00690 {
00691
00692 d->worldPosition = d->position;
00693 d->worldOrientation = d->orientation;
00694 d->worldScale = d->scale;
00695 }
00696
00697
00698 d->transform.setToIdentity();
00699 d->transform.translate( d->worldPosition );
00700 d->transform.rotate( d->worldOrientation );
00701 d->transform.scale( d->worldScale );
00702
00703
00704 foreach( GameObject * child, d->children )
00705 {
00706 child->invalidateTransform();
00707 child->updateTransform();
00708 }
00709
00710 d->transformInvalidated = false;
00711 }
00712
00713 void GameObject::invalidateTransform()
00714 {
00715 d->transformInvalidated = true;
00716 }
00717
00718 QMatrix4x4
00719 GameObject::transform() const
00720 {
00721 return d->transform;
00722 }
00723
00724 void
00725 GameObject::postCloneSanitize()
00726 {
00727 foreach( QObject * child, children() )
00728 {
00729 if( qobject_cast<Component*>( child ) )
00730 {
00731 Component* comp = qobject_cast<Component*>( child );
00732 d->components.append( comp );
00733 int typeID = QMetaType::type( comp->metaObject()->className() );
00734 d->componentTypes.insert( typeID, comp );
00735 comp->setParent( this );
00736 comp->setGameObject( this );
00737 }
00738 }
00739
00740 if( Game::instance()->isRunning() )
00741 {
00742 initialize();
00743 start();
00744 }
00745
00746 GluonCore::GluonObject::postCloneSanitize();
00747 }
00748
00749 #include "gameobject.moc"