Touch.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //
  2. // Copyright (c) 2008-2014 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 "BorderImage.h"
  23. #include "Camera.h"
  24. #include "Character.h"
  25. #include "Controls.h"
  26. #include "Drawable.h"
  27. #include "Graphics.h"
  28. #include "Input.h"
  29. #include "InputEvents.h"
  30. #include "Log.h"
  31. #include "Octree.h"
  32. #include "PhysicsWorld.h"
  33. #include "Renderer.h"
  34. #include "ResourceCache.h"
  35. #include "RigidBody.h"
  36. #include "Scene.h"
  37. #include "Texture2D.h"
  38. #include "Touch.h"
  39. #include "UI.h"
  40. Touch::Touch(Context* context) :
  41. Object(context),
  42. cameraDistance_(CAMERA_INITIAL_DIST),
  43. touchButtonSize_(96),
  44. touchButtonBorder_(12),
  45. moveTouchID_(-1),
  46. rotateTouchID_(-1),
  47. fireTouchID_(-1),
  48. firstPerson_(false),
  49. newFirstPerson_(false),
  50. shadowMode_(false),
  51. zoom_(false),
  52. touchEnabled_(false)
  53. {
  54. }
  55. Touch::~Touch()
  56. {
  57. }
  58. void Touch::InitTouchInput()
  59. {
  60. UI* ui = GetSubsystem<UI>();
  61. ResourceCache* cache = GetSubsystem<ResourceCache>();
  62. moveButton_ = ui->GetRoot()->CreateChild<BorderImage>();
  63. moveButton_->SetTexture(cache->GetResource<Texture2D>("Textures/TouchInput.png"));
  64. moveButton_->SetImageRect(IntRect(0, 0, 96, 96));
  65. moveButton_->SetAlignment(HA_LEFT, VA_BOTTOM);
  66. moveButton_->SetPosition(touchButtonBorder_, -touchButtonBorder_);
  67. moveButton_->SetSize(touchButtonSize_, touchButtonSize_);
  68. moveButton_->SetOpacity(0.25f);
  69. fireButton_ = ui->GetRoot()->CreateChild<BorderImage>();
  70. fireButton_->SetTexture(cache->GetResource<Texture2D>("Textures/TouchInput.png"));
  71. fireButton_->SetImageRect(IntRect(96, 0, 192, 96));
  72. fireButton_->SetAlignment(HA_RIGHT, VA_BOTTOM);
  73. fireButton_->SetPosition(-touchButtonBorder_, -touchButtonBorder_);
  74. fireButton_->SetSize(touchButtonSize_, touchButtonSize_);
  75. fireButton_->SetOpacity(0.25f);
  76. touchEnabled_ = true;
  77. }
  78. void Touch::SubscribeToTouchEvents()
  79. {
  80. SubscribeToEvent(E_TOUCHBEGIN, HANDLER(Touch, HandleTouchBegin));
  81. SubscribeToEvent(E_TOUCHEND, HANDLER(Touch, HandleTouchEnd));
  82. }
  83. void Touch::UpdateTouches(Controls& controls) // Called from HandleUpdate
  84. {
  85. if (!scene_ || !cameraNode_)
  86. return;
  87. Camera* camera = cameraNode_->GetComponent<Camera>();
  88. if (!camera)
  89. return;
  90. zoom_ = false; // reset bool
  91. Graphics* graphics = GetSubsystem<Graphics>();
  92. Input* input = GetSubsystem<Input>();
  93. // Touch Inputs
  94. if (touchEnabled_)
  95. {
  96. // Zoom in/out
  97. if (input->GetNumTouches() == 2)
  98. {
  99. TouchState* touch1 = input->GetTouch(0);
  100. TouchState* touch2 = input->GetTouch(1);
  101. // Check for zoom pattern (touches moving in opposite directions)
  102. if ((touch1->delta_.y_ > 0 && touch2->delta_.y_ < 0) || (touch1->delta_.y_ < 0 && touch2->delta_.y_ > 0))
  103. zoom_ = true;
  104. else
  105. zoom_ = false;
  106. if (zoom_)
  107. {
  108. int sens = 0;
  109. // Check for zoom direction (in/out)
  110. if (Abs(touch1->position_.y_ - touch2->position_.y_) > Abs(touch1->lastPosition_.y_ - touch2->lastPosition_.y_))
  111. sens = -1;
  112. else
  113. sens = 1;
  114. cameraDistance_ += Abs(touch1->delta_.y_ - touch2->delta_.y_) * sens * TOUCH_SENSITIVITY / 50.0f;
  115. cameraDistance_ = Clamp(cameraDistance_, CAMERA_MIN_DIST, CAMERA_MAX_DIST); // Restrict zoom range to [1;20]
  116. }
  117. }
  118. // Switch 1st/3rd person mode
  119. if (input->GetNumTouches() == 3)
  120. newFirstPerson_ = !firstPerson_;
  121. // Switch draw debug
  122. if (input->GetNumTouches() == 4)
  123. shadowMode_ = !GetSubsystem<Renderer>()->GetDrawShadows();
  124. // Rotate and Move
  125. if (!zoom_)
  126. {
  127. for (unsigned i = 0; i < input->GetNumTouches(); ++i)
  128. {
  129. TouchState* touch = input->GetTouch(i);
  130. if (touch->touchID_ == rotateTouchID_)
  131. {
  132. controls.yaw_ += TOUCH_SENSITIVITY * camera->GetFov() / (float)graphics->GetHeight() * touch->delta_.x_;
  133. controls.pitch_ += TOUCH_SENSITIVITY * camera->GetFov() / (float)graphics->GetHeight() * touch->delta_.y_;
  134. controls.pitch_ = Clamp(controls.pitch_, -80.0f, 80.0f); // Limit pitch
  135. }
  136. if (touch->touchID_ == moveTouchID_)
  137. {
  138. int relX = touch->position_.x_ - moveButton_->GetScreenPosition().x_ - touchButtonSize_ / 2;
  139. int relY = touch->position_.y_ - moveButton_->GetScreenPosition().y_ - touchButtonSize_ / 2;
  140. if (relY < 0 && Abs(relX * 3 / 2) < Abs(relY))
  141. controls.Set(CTRL_FORWARD, true);
  142. if (relY > 0 && Abs(relX * 3 / 2) < Abs(relY))
  143. controls.Set(CTRL_BACK, true);
  144. if (relX < 0 && Abs(relY * 3 / 2) < Abs(relX))
  145. controls.Set(CTRL_LEFT, true);
  146. if (relX > 0 && Abs(relY * 3 / 2) < Abs(relX))
  147. controls.Set(CTRL_RIGHT, true);
  148. }
  149. }
  150. }
  151. if (fireTouchID_ >= 0)
  152. controls.Set(CTRL_JUMP, true);
  153. }
  154. // Gyroscope (emulated by SDL through a virtual joystick)
  155. if (input->GetNumJoysticks() > 0) // numJoysticks = 1 on iOS & Android
  156. {
  157. JoystickState* joystick = input->GetJoystick(0);
  158. if (joystick->GetNumAxes() >= 2)
  159. {
  160. if (joystick->GetAxisPosition(0) < -GYROSCOPE_THRESHOLD)
  161. controls.Set(CTRL_LEFT, true);
  162. if (joystick->GetAxisPosition(0) > GYROSCOPE_THRESHOLD)
  163. controls.Set(CTRL_RIGHT, true);
  164. if (joystick->GetAxisPosition(1) < -GYROSCOPE_THRESHOLD)
  165. controls.Set(CTRL_FORWARD, true);
  166. if (joystick->GetAxisPosition(1) > GYROSCOPE_THRESHOLD)
  167. controls.Set(CTRL_BACK, true);
  168. }
  169. }
  170. }
  171. void Touch::HandleTouchBegin(StringHash eventType, VariantMap& eventData)
  172. {
  173. using namespace TouchBegin;
  174. int touchID = eventData[P_TOUCHID].GetInt(); // Get #touches or dragging value
  175. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt()); // Get touch coordinates
  176. UI* ui = GetSubsystem<UI>();
  177. UIElement* element = ui->GetElementAt(pos, false); // Get gamepad UIElement touched (if any)
  178. // Check for gamepad button touched. If none, rotate
  179. if (element == moveButton_)
  180. moveTouchID_ = touchID;
  181. else if (element == fireButton_)
  182. fireTouchID_ = touchID;
  183. else
  184. rotateTouchID_ = touchID;
  185. // Init Raycast (for example to acquire a target)
  186. if (!cameraNode_ || !scene_)
  187. return;
  188. Camera* camera = cameraNode_->GetComponent<Camera>();
  189. if (!camera)
  190. return;
  191. Graphics* graphics = GetSubsystem<Graphics>();
  192. Ray cameraRay = camera->GetScreenRay((float)pos.x_ / (float)graphics->GetWidth(), (float)pos.y_ / (float)graphics->GetHeight());
  193. // Raycast of RigidBodies
  194. PhysicsRaycastResult result;
  195. scene_->GetComponent<PhysicsWorld>()->RaycastSingle(result, cameraRay, camera->GetFarClip(), 2); // NB: here we restrict targets to layer 2
  196. if (result.body_)
  197. LOGINFO("Physics raycast hit " + result.body_->GetNode()->GetName());
  198. // Raycast of drawable components (for targets without physics)
  199. PODVector<RayQueryResult> result2;
  200. RayOctreeQuery rayQuery(result2, cameraRay, RAY_TRIANGLE, camera->GetFarClip(), DRAWABLE_GEOMETRY);
  201. scene_->GetComponent<Octree>()->RaycastSingle(rayQuery);
  202. if (result2.Size())
  203. LOGINFO("Drawable raycast hit " + result2[0].drawable_->GetNode()->GetName());
  204. }
  205. void Touch::HandleTouchEnd(StringHash eventType, VariantMap& eventData)
  206. {
  207. using namespace TouchBegin;
  208. int touchID = eventData[P_TOUCHID].GetInt();
  209. if (touchID == moveTouchID_)
  210. moveTouchID_ = -1;
  211. if (touchID == rotateTouchID_)
  212. rotateTouchID_ = -1;
  213. if (touchID == fireTouchID_)
  214. fireTouchID_ = -1;
  215. // On-release Update
  216. firstPerson_ = newFirstPerson_;
  217. GetSubsystem<Renderer>()->SetDrawShadows(shadowMode_);
  218. }