Character2D.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include <Urho3D/Core/Context.h>
  4. #include <Urho3D/Input/Input.h>
  5. #include <Urho3D/Physics2D/RigidBody2D.h>
  6. #include <Urho3D/Scene/Scene.h>
  7. #include <Urho3D/Scene/SceneEvents.h>
  8. #include <Urho3D/UI/Text.h>
  9. #include <Urho3D/UI/UI.h>
  10. #include <Urho3D/Urho2D/AnimatedSprite2D.h>
  11. #include <Urho3D/Urho2D/AnimationSet2D.h>
  12. #include "Character2D.h"
  13. #include <Urho3D/DebugNew.h>
  14. // Character2D logic component
  15. Character2D::Character2D(Context* context) :
  16. LogicComponent(context),
  17. wounded_(false),
  18. killed_(false),
  19. timer_(0.0f),
  20. maxCoins_(0),
  21. remainingCoins_(0),
  22. remainingLifes_(3),
  23. moveSpeedScale_(1.0f),
  24. zoom_(0.0f)
  25. {
  26. }
  27. void Character2D::RegisterObject(Context* context)
  28. {
  29. context->RegisterFactory<Character2D>();
  30. // These macros register the class attributes to the Context for automatic load / save handling.
  31. // We specify the 'Default' attribute mode which means it will be used both for saving into file, and network replication.
  32. URHO3D_ATTRIBUTE("Move Speed Scale", moveSpeedScale_, 1.0f, AM_DEFAULT);
  33. URHO3D_ATTRIBUTE("Camera Zoom", zoom_, 0.0f, AM_DEFAULT);
  34. URHO3D_ATTRIBUTE("Coins In Level", maxCoins_, 0, AM_DEFAULT);
  35. URHO3D_ATTRIBUTE("Remaining Coins", remainingCoins_, 0, AM_DEFAULT);
  36. URHO3D_ATTRIBUTE("Remaining Lifes", remainingLifes_, 3, AM_DEFAULT);
  37. }
  38. void Character2D::Update(float timeStep)
  39. {
  40. // Handle wounded/killed states
  41. if (killed_)
  42. return;
  43. if (wounded_)
  44. {
  45. HandleWoundedState(timeStep);
  46. return;
  47. }
  48. auto* animatedSprite = GetComponent<AnimatedSprite2D>();
  49. auto* input = GetSubsystem<Input>();
  50. // Set direction
  51. Vector3 moveDir = Vector3::ZERO; // Reset
  52. float speedX = Clamp(MOVE_SPEED_X / zoom_, 0.4f, 1.0f);
  53. float speedY = speedX;
  54. if (input->GetKeyDown(KEY_A) || input->GetKeyDown(KEY_LEFT))
  55. {
  56. moveDir = moveDir + Vector3::LEFT * speedX;
  57. animatedSprite->SetFlipX(false); // Flip sprite (reset to default play on the X axis)
  58. }
  59. if (input->GetKeyDown(KEY_D) || input->GetKeyDown(KEY_RIGHT))
  60. {
  61. moveDir = moveDir + Vector3::RIGHT * speedX;
  62. animatedSprite->SetFlipX(true); // Flip sprite (flip animation on the X axis)
  63. }
  64. if (!moveDir.Equals(Vector3::ZERO))
  65. speedY = speedX * moveSpeedScale_;
  66. if (input->GetKeyDown(KEY_W) || input->GetKeyDown(KEY_UP))
  67. moveDir = moveDir + Vector3::UP * speedY;
  68. if (input->GetKeyDown(KEY_S) || input->GetKeyDown(KEY_DOWN))
  69. moveDir = moveDir + Vector3::DOWN * speedY;
  70. // Move
  71. if (!moveDir.Equals(Vector3::ZERO))
  72. node_->Translate(moveDir * timeStep);
  73. // Animate
  74. if (input->GetKeyDown(KEY_SPACE))
  75. {
  76. if (animatedSprite->GetAnimation() != "attack")
  77. animatedSprite->SetAnimation("attack", LM_FORCE_LOOPED);
  78. }
  79. else if (!moveDir.Equals(Vector3::ZERO))
  80. {
  81. if (animatedSprite->GetAnimation() != "run")
  82. animatedSprite->SetAnimation("run");
  83. }
  84. else if (animatedSprite->GetAnimation() != "idle")
  85. {
  86. animatedSprite->SetAnimation("idle");
  87. }
  88. }
  89. void Character2D::HandleWoundedState(float timeStep)
  90. {
  91. auto* body = GetComponent<RigidBody2D>();
  92. auto* animatedSprite = GetComponent<AnimatedSprite2D>();
  93. // Play "hit" animation in loop
  94. if (animatedSprite->GetAnimation() != "hit")
  95. animatedSprite->SetAnimation("hit", LM_FORCE_LOOPED);
  96. // Update timer
  97. timer_ += timeStep;
  98. if (timer_ > 2.0f)
  99. {
  100. // Reset timer
  101. timer_ = 0.0f;
  102. // Clear forces (should be performed by setting linear velocity to zero, but currently doesn't work)
  103. body->SetLinearVelocity(Vector2::ZERO);
  104. body->SetAwake(false);
  105. body->SetAwake(true);
  106. // Remove particle emitter
  107. node_->GetChild("Emitter", true)->Remove();
  108. // Update lifes UI and counter
  109. remainingLifes_ -= 1;
  110. auto* ui = GetSubsystem<UI>();
  111. Text* lifeText = static_cast<Text*>(ui->GetRoot()->GetChild("LifeText", true));
  112. lifeText->SetText(String(remainingLifes_)); // Update lifes UI counter
  113. // Reset wounded state
  114. wounded_ = false;
  115. // Handle death
  116. if (remainingLifes_ == 0)
  117. {
  118. HandleDeath();
  119. return;
  120. }
  121. // Re-position the character to the nearest point
  122. if (node_->GetPosition().x_ < 15.0f)
  123. node_->SetPosition(Vector3(-5.0f, 11.0f, 0.0f));
  124. else
  125. node_->SetPosition(Vector3(18.8f, 9.2f, 0.0f));
  126. }
  127. }
  128. void Character2D::HandleDeath()
  129. {
  130. auto* body = GetComponent<RigidBody2D>();
  131. auto* animatedSprite = GetComponent<AnimatedSprite2D>();
  132. // Set state to 'killed'
  133. killed_ = true;
  134. // Update UI elements
  135. auto* ui = GetSubsystem<UI>();
  136. Text* instructions = static_cast<Text*>(ui->GetRoot()->GetChild("Instructions", true));
  137. instructions->SetText("!!! GAME OVER !!!");
  138. static_cast<Text*>(ui->GetRoot()->GetChild("ExitButton", true))->SetVisible(true);
  139. static_cast<Text*>(ui->GetRoot()->GetChild("PlayButton", true))->SetVisible(true);
  140. // Show mouse cursor so that we can click
  141. auto* input = GetSubsystem<Input>();
  142. input->SetMouseVisible(true);
  143. // Put character outside of the scene and magnify him
  144. node_->SetPosition(Vector3(-20.0f, 0.0f, 0.0f));
  145. node_->SetScale(1.2f);
  146. // Play death animation once
  147. if (animatedSprite->GetAnimation() != "dead")
  148. animatedSprite->SetAnimation("dead");
  149. }