game_object.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright (c) 2022-2023 the Dviglo project
  2. // Copyright (c) 2008-2023 the Urho3D project
  3. // License: MIT
  4. #include "game_object.h"
  5. namespace Urho3D
  6. {
  7. void GameObject::RegisterObject(Context* context)
  8. {
  9. context->RegisterFactory<GameObject>();
  10. }
  11. GameObject::GameObject(Context* context)
  12. : LogicComponent(context)
  13. , onGround(false)
  14. , isSliding(false)
  15. , duration(-1) // Бесконечно
  16. , health(0)
  17. , maxHealth(0)
  18. , side(SIDE_NEUTRAL)
  19. , lastDamageSide(SIDE_NEUTRAL)
  20. , lastDamageCreatorID(0)
  21. , creatorID(0)
  22. {
  23. SetUpdateEventMask(LogicComponentEvents::FixedUpdate);
  24. // if (runClient)
  25. // Print("Warning! Logic object created on client!");
  26. }
  27. void GameObject::FixedUpdate(float timeStep)
  28. {
  29. // Disappear when duration expired
  30. if (duration >= 0)
  31. {
  32. duration -= timeStep;
  33. if (duration <= 0)
  34. node_->Remove();
  35. }
  36. }
  37. bool GameObject::Damage(GameObject& origin, i32 amount)
  38. {
  39. if (origin.side == side || health == 0)
  40. return false;
  41. lastDamageSide = origin.side;
  42. lastDamageCreatorID = origin.creatorID;
  43. health -= amount;
  44. if (health < 0)
  45. health = 0;
  46. return true;
  47. }
  48. bool GameObject::Heal(i32 amount)
  49. {
  50. // By default do not heal
  51. return false;
  52. }
  53. void GameObject::PlaySound(const String& soundName)
  54. {
  55. SoundSource3D* source = node_->CreateComponent<SoundSource3D>();
  56. Sound* sound = GetSubsystem<ResourceCache>()->GetResource<Sound>(soundName);
  57. // Subscribe to sound finished for cleaning up the source
  58. SubscribeToEvent(node_, E_SOUNDFINISHED, URHO3D_HANDLER(GameObject, HandleSoundFinished));
  59. source->SetDistanceAttenuation(2, 50, 1);
  60. source->Play(sound);
  61. }
  62. void GameObject::HandleSoundFinished(StringHash eventType, VariantMap& eventData)
  63. {
  64. using namespace SoundFinished;
  65. SoundSource3D* source = static_cast<SoundSource3D*>(eventData[P_SOUNDSOURCE].GetPtr());
  66. source->Remove();
  67. }
  68. void GameObject::HandleNodeCollision(StringHash eventType, VariantMap& eventData)
  69. {
  70. using namespace NodeCollision;
  71. Node* otherNode = static_cast<Node*>(eventData[P_OTHERNODE].GetPtr());
  72. RigidBody* otherBody = static_cast<RigidBody*>(eventData[P_OTHERBODY].GetPtr());
  73. // If the other collision shape belongs to static geometry, perform world collision
  74. if (otherBody->GetCollisionLayer() == 2)
  75. WorldCollision(eventData);
  76. // If the other node is scripted, perform object-to-object collision
  77. GameObject* otherObject = otherNode->GetDerivedComponent<GameObject>();
  78. if (otherObject)
  79. ObjectCollision(*otherObject, eventData);
  80. }
  81. void GameObject::WorldCollision(VariantMap& eventData)
  82. {
  83. using namespace NodeCollision;
  84. MemoryBuffer contacts(eventData[P_CONTACTS].GetBuffer());
  85. while (!contacts.IsEof())
  86. {
  87. Vector3 contactPosition = contacts.ReadVector3();
  88. Vector3 contactNormal = contacts.ReadVector3();
  89. float contactDistance = contacts.ReadFloat();
  90. float contactImpulse = contacts.ReadFloat();
  91. // If contact is below node center and pointing up, assume it's ground contact
  92. if (contactPosition.y_ < node_->GetPosition().y_)
  93. {
  94. float level = contactNormal.y_;
  95. if (level > 0.75)
  96. {
  97. onGround = true;
  98. }
  99. else
  100. {
  101. // If contact is somewhere between vertical/horizontal, is sliding a slope
  102. if (level > 0.1)
  103. isSliding = true;
  104. }
  105. }
  106. }
  107. // Ground contact has priority over sliding contact
  108. if (onGround == true)
  109. isSliding = false;
  110. }
  111. void GameObject::ObjectCollision(GameObject& otherObject, VariantMap& eventData)
  112. {
  113. }
  114. void GameObject::ResetWorldCollision()
  115. {
  116. RigidBody* body = node_->GetComponent<RigidBody>();
  117. if (body->IsActive())
  118. {
  119. onGround = false;
  120. isSliding = false;
  121. }
  122. else
  123. {
  124. // If body is not active, assume it rests on the ground
  125. onGround = true;
  126. isSliding = false;
  127. }
  128. }
  129. } // namespace Urho3D