Character2D.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. //
  2. // Copyright (c) 2008-2020 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Urho3D/Urho2D/AnimatedSprite2D.h>
  23. #include <Urho3D/Urho2D/AnimationSet2D.h>
  24. #include <Urho3D/Core/Context.h>
  25. #include <Urho3D/Input/Input.h>
  26. #include <Urho3D/Urho2D/RigidBody2D.h>
  27. #include <Urho3D/Scene/Scene.h>
  28. #include <Urho3D/Scene/SceneEvents.h>
  29. #include <Urho3D/UI/Text.h>
  30. #include <Urho3D/UI/UI.h>
  31. #include "Character2D.h"
  32. #include <Urho3D/DebugNew.h>
  33. // Character2D logic component
  34. Character2D::Character2D(Context* context) :
  35. LogicComponent(context),
  36. wounded_(false),
  37. killed_(false),
  38. timer_(0.0f),
  39. maxCoins_(0),
  40. remainingCoins_(0),
  41. remainingLifes_(3),
  42. moveSpeedScale_(1.0f),
  43. zoom_(0.0f)
  44. {
  45. }
  46. void Character2D::RegisterObject(Context* context)
  47. {
  48. context->RegisterFactory<Character2D>();
  49. // These macros register the class attributes to the Context for automatic load / save handling.
  50. // We specify the 'Default' attribute mode which means it will be used both for saving into file, and network replication.
  51. URHO3D_ATTRIBUTE("Move Speed Scale", float, moveSpeedScale_, 1.0f, AM_DEFAULT);
  52. URHO3D_ATTRIBUTE("Camera Zoom", float, zoom_, 0.0f, AM_DEFAULT);
  53. URHO3D_ATTRIBUTE("Coins In Level", int, maxCoins_, 0, AM_DEFAULT);
  54. URHO3D_ATTRIBUTE("Remaining Coins", int, remainingCoins_, 0, AM_DEFAULT);
  55. URHO3D_ATTRIBUTE("Remaining Lifes", int, remainingLifes_, 3, AM_DEFAULT);
  56. }
  57. void Character2D::Update(float timeStep)
  58. {
  59. // Handle wounded/killed states
  60. if (killed_)
  61. return;
  62. if (wounded_)
  63. {
  64. HandleWoundedState(timeStep);
  65. return;
  66. }
  67. auto* animatedSprite = GetComponent<AnimatedSprite2D>();
  68. auto* input = GetSubsystem<Input>();
  69. // Set direction
  70. Vector3 moveDir = Vector3::ZERO; // Reset
  71. float speedX = Clamp(MOVE_SPEED_X / zoom_, 0.4f, 1.0f);
  72. float speedY = speedX;
  73. if (input->GetKeyDown(KEY_A) || input->GetKeyDown(KEY_LEFT))
  74. {
  75. moveDir = moveDir + Vector3::LEFT * speedX;
  76. animatedSprite->SetFlipX(false); // Flip sprite (reset to default play on the X axis)
  77. }
  78. if (input->GetKeyDown(KEY_D) || input->GetKeyDown(KEY_RIGHT))
  79. {
  80. moveDir = moveDir + Vector3::RIGHT * speedX;
  81. animatedSprite->SetFlipX(true); // Flip sprite (flip animation on the X axis)
  82. }
  83. if (!moveDir.Equals(Vector3::ZERO))
  84. speedY = speedX * moveSpeedScale_;
  85. if (input->GetKeyDown(KEY_W) || input->GetKeyDown(KEY_UP))
  86. moveDir = moveDir + Vector3::UP * speedY;
  87. if (input->GetKeyDown(KEY_S) || input->GetKeyDown(KEY_DOWN))
  88. moveDir = moveDir + Vector3::DOWN * speedY;
  89. // Move
  90. if (!moveDir.Equals(Vector3::ZERO))
  91. node_->Translate(moveDir * timeStep);
  92. // Animate
  93. if (input->GetKeyDown(KEY_SPACE))
  94. {
  95. if (animatedSprite->GetAnimation() != "attack")
  96. animatedSprite->SetAnimation("attack", LM_FORCE_LOOPED);
  97. }
  98. else if (!moveDir.Equals(Vector3::ZERO))
  99. {
  100. if (animatedSprite->GetAnimation() != "run")
  101. animatedSprite->SetAnimation("run");
  102. }
  103. else if (animatedSprite->GetAnimation() != "idle")
  104. {
  105. animatedSprite->SetAnimation("idle");
  106. }
  107. }
  108. void Character2D::HandleWoundedState(float timeStep)
  109. {
  110. auto* body = GetComponent<RigidBody2D>();
  111. auto* animatedSprite = GetComponent<AnimatedSprite2D>();
  112. // Play "hit" animation in loop
  113. if (animatedSprite->GetAnimation() != "hit")
  114. animatedSprite->SetAnimation("hit", LM_FORCE_LOOPED);
  115. // Update timer
  116. timer_ += timeStep;
  117. if (timer_ > 2.0f)
  118. {
  119. // Reset timer
  120. timer_ = 0.0f;
  121. // Clear forces (should be performed by setting linear velocity to zero, but currently doesn't work)
  122. body->SetLinearVelocity(Vector2::ZERO);
  123. body->SetAwake(false);
  124. body->SetAwake(true);
  125. // Remove particle emitter
  126. node_->GetChild("Emitter", true)->Remove();
  127. // Update lifes UI and counter
  128. remainingLifes_ -= 1;
  129. auto* ui = GetSubsystem<UI>();
  130. Text* lifeText = static_cast<Text*>(ui->GetRoot()->GetChild("LifeText", true));
  131. lifeText->SetText(String(remainingLifes_)); // Update lifes UI counter
  132. // Reset wounded state
  133. wounded_ = false;
  134. // Handle death
  135. if (remainingLifes_ == 0)
  136. {
  137. HandleDeath();
  138. return;
  139. }
  140. // Re-position the character to the nearest point
  141. if (node_->GetPosition().x_ < 15.0f)
  142. node_->SetPosition(Vector3(-5.0f, 11.0f, 0.0f));
  143. else
  144. node_->SetPosition(Vector3(18.8f, 9.2f, 0.0f));
  145. }
  146. }
  147. void Character2D::HandleDeath()
  148. {
  149. auto* body = GetComponent<RigidBody2D>();
  150. auto* animatedSprite = GetComponent<AnimatedSprite2D>();
  151. // Set state to 'killed'
  152. killed_ = true;
  153. // Update UI elements
  154. auto* ui = GetSubsystem<UI>();
  155. Text* instructions = static_cast<Text*>(ui->GetRoot()->GetChild("Instructions", true));
  156. instructions->SetText("!!! GAME OVER !!!");
  157. static_cast<Text*>(ui->GetRoot()->GetChild("ExitButton", true))->SetVisible(true);
  158. static_cast<Text*>(ui->GetRoot()->GetChild("PlayButton", true))->SetVisible(true);
  159. // Show mouse cursor so that we can click
  160. auto* input = GetSubsystem<Input>();
  161. input->SetMouseVisible(true);
  162. // Put character outside of the scene and magnify him
  163. node_->SetPosition(Vector3(-20.0f, 0.0f, 0.0f));
  164. node_->SetScale(1.2f);
  165. // Play death animation once
  166. if (animatedSprite->GetAnimation() != "dead")
  167. animatedSprite->SetAnimation("dead");
  168. }