Joystick.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. #include "Base.h"
  2. #include "Joystick.h"
  3. #define INVALID_CONTACT_INDEX ((unsigned int)-1)
  4. namespace gameplay
  5. {
  6. Joystick::Joystick() : _contactIndex(INVALID_CONTACT_INDEX), _absolute(true)
  7. {
  8. }
  9. Joystick::Joystick(const Joystick& copy)
  10. {
  11. }
  12. Joystick::~Joystick()
  13. {
  14. }
  15. Joystick* Joystick::create(Theme::Style* style, Properties* properties)
  16. {
  17. Joystick* joystick = new Joystick();
  18. joystick->initialize(style, properties);
  19. joystick->_consumeTouchEvents = false;
  20. return joystick;
  21. }
  22. void Joystick::initialize(Theme::Style* style, Properties* properties)
  23. {
  24. GP_ASSERT(properties);
  25. Control::initialize(style, properties);
  26. if (!properties->exists("radius"))
  27. {
  28. GP_ERROR("Failed to load joystick; required attribute 'radius' is missing.");
  29. return;
  30. }
  31. _radius = properties->getFloat("radius");
  32. Vector4 v;
  33. if (properties->getVector4("region", &v))
  34. {
  35. _absolute = false;
  36. _region = _bounds;
  37. _bounds.x = v.x;
  38. _bounds.y = v.y;
  39. _bounds.width = v.z;
  40. _bounds.height = v.w;
  41. }
  42. }
  43. void Joystick::addListener(Control::Listener* listener, int eventFlags)
  44. {
  45. if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
  46. {
  47. GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
  48. }
  49. _consumeTouchEvents = true;
  50. Control::addListener(listener, eventFlags);
  51. }
  52. bool Joystick::touchEvent(Touch::TouchEvent touchEvent, int x, int y, unsigned int contactIndex)
  53. {
  54. switch (touchEvent)
  55. {
  56. case Touch::TOUCH_PRESS:
  57. {
  58. float dx = 0.0f;
  59. float dy = 0.0f;
  60. if (_absolute)
  61. {
  62. dx = x - _bounds.width * 0.5f;
  63. dy = _bounds.height * 0.5f - y;
  64. }
  65. else
  66. {
  67. _region.x = x + _bounds.x - _region.width * 0.5f;
  68. _region.y = y + _bounds.y - _region.height * 0.5f;
  69. }
  70. if ((dx >= -_radius && dx <= _radius) && (dy >= -_radius && dy <= _radius) &&
  71. _contactIndex == INVALID_CONTACT_INDEX)
  72. {
  73. _contactIndex = contactIndex;
  74. _displacement.set(0.0f, 0.0f);
  75. Vector2 value(0.0f, 0.0f);
  76. if (_value != value)
  77. {
  78. _value.set(value);
  79. notifyListeners(Control::Listener::VALUE_CHANGED);
  80. }
  81. _state = ACTIVE;
  82. }
  83. }
  84. case Touch::TOUCH_MOVE:
  85. {
  86. if (_contactIndex == contactIndex)
  87. {
  88. float dx = x - ((!_absolute) ? _region.x - _bounds.x : 0.0f) - _region.width * 0.5f;
  89. float dy = -(y - ((!_absolute) ? _region.y - _bounds.y : 0.0f) - _region.height * 0.5f);
  90. if (((dx * dx) + (dy * dy)) <= (_radius * _radius))
  91. {
  92. GP_ASSERT(_radius);
  93. Vector2 value(dx, dy);
  94. value.scale(1.0f / _radius);
  95. if (_value != value)
  96. {
  97. _value.set(value);
  98. notifyListeners(Control::Listener::VALUE_CHANGED);
  99. }
  100. }
  101. else
  102. {
  103. Vector2 value(dx, dy);
  104. value.normalize();
  105. value.scale(_radius);
  106. value.normalize();
  107. if (_value != value)
  108. {
  109. _value.set(value);
  110. notifyListeners(Control::Listener::VALUE_CHANGED);
  111. }
  112. }
  113. _displacement.set(dx, dy);
  114. }
  115. }
  116. break;
  117. case Touch::TOUCH_RELEASE:
  118. {
  119. if (_contactIndex == contactIndex)
  120. {
  121. // Reset displacement and direction vectors.
  122. _contactIndex = INVALID_CONTACT_INDEX;
  123. _displacement.set(0.0f, 0.0f);
  124. Vector2 value(0.0f, 0.0f);
  125. if (_value != value)
  126. {
  127. _value.set(value);
  128. notifyListeners(Control::Listener::VALUE_CHANGED);
  129. }
  130. _state = NORMAL;
  131. }
  132. }
  133. break;
  134. }
  135. return Control::touchEvent(touchEvent, x, y, contactIndex);
  136. }
  137. void Joystick::update(const Rectangle& clip, const Vector2& offset)
  138. {
  139. Control::update(clip, offset);
  140. }
  141. void Joystick::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
  142. {
  143. GP_ASSERT(spriteBatch);
  144. spriteBatch->begin();
  145. // If the joystick is not absolute, then only draw if it is active.
  146. if (_absolute || (!_absolute && _state == ACTIVE))
  147. {
  148. if (_absolute)
  149. _region = _bounds;
  150. // Draw the outer image.
  151. Theme::ThemeImage* outer = getImage("outer", _state);
  152. if (outer)
  153. {
  154. // Get the uvs and color and draw.
  155. const Theme::UVs& uvs = outer->getUVs();
  156. const Vector4& color = outer->getColor();
  157. spriteBatch->draw(_region.x, _region.y, _region.width, _region.height, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
  158. }
  159. // Draw the inner image.
  160. Theme::ThemeImage* inner = getImage("inner", _state);
  161. if (inner)
  162. {
  163. Rectangle region = _region;
  164. // Adjust position to reflect displacement.
  165. if (((_displacement.x * _displacement.x) + (_displacement.y * _displacement.y)) <= (_radius * _radius))
  166. {
  167. region.x += _displacement.x;
  168. region.y += -_displacement.y;
  169. }
  170. else
  171. {
  172. // Find the point on the joystick's circular bound where the
  173. // vector intersects. This is the position of the inner image.
  174. Vector2 delta = Vector2(_displacement.x, -_displacement.y);
  175. delta.normalize();
  176. delta.scale(_radius);
  177. region.x += delta.x;
  178. region.y += delta.y;
  179. }
  180. // Get the uvs and color and draw.
  181. const Theme::UVs& uvs = inner->getUVs();
  182. const Vector4& color = inner->getColor();
  183. spriteBatch->draw(region.x, region.y, _region.width, _region.height, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
  184. }
  185. }
  186. spriteBatch->end();
  187. }
  188. }