Angel 3.2
A 2D Game Prototyping Engine
MobileSimulator.cpp
1 
2 // Copyright (C) 2008-2013, Shane Liesegang
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of the copyright holder nor the names of any
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "stdafx.h"
31 #include "../Input/MobileSimulator.h"
32 
33 #include "../Actors/Actor.h"
34 #include "../Input/InputManager.h"
35 #include "../Input/MultiTouch.h"
36 #include "../Messaging/Switchboard.h"
37 
38 // maximum duration of touch (in seconds) to be considered a swipe
39 // (too long and we're dragging)
40 #define SWIPE_MAX_DURATION 0.4f
41 // distance in pixels the touch must go to be considered a swipe
42 // (too short and it might have just been a tap)
43 #define SWIPE_MIN_DISTANCE 50
44 
45 // distance in pixels that the touches have to move before multi-touch
46 // recognition starts
47 #define MULTI_MIN_DISTANCE 13
48 // angle in radians that the touches' vectors need to shift by to
49 // be considered a rotation instead of a pinch
50 // (equivalent of 2.5 degrees)
51 #define MULTI_ROTATE_ANGLE 0.0436332313f
52 
53 MobileSimulator::MobileSimulator()
54 {
55  _multiGestureOngoing = false;
56  _gestureType = NONE;
57  _mouseDown = false;
58 
59  _fingerGhost1 = new Actor();
60  _fingerGhost1->SetSize(1.5f);
61  _fingerGhost1->SetDrawShape(ADS_Circle);
62  _fingerGhost1->SetColor(0.8f, 0.8f, 0.8f, 0.0f);
63 
64  _fingerGhost2 = new Actor();
65  _fingerGhost2->SetSize(1.5f);
66  _fingerGhost2->SetDrawShape(ADS_Circle);
67  _fingerGhost2->SetColor(0.8f, 0.8f, 0.8f, 0.0f);
68 
69 
70  theWorld.Add(_fingerGhost1, 1000);
71  theWorld.Add(_fingerGhost2, 1000);
72 }
73 
74 MobileSimulator::~MobileSimulator()
75 {
76 
77 }
78 
80 {
81  if (theInput.IsKeyDown(ANGEL_KEY_LEFTCONTROL) || theInput.IsKeyDown(ANGEL_KEY_RIGHTCONTROL))
82  {
83  _fingerGhost1->SetAlpha(0.5f);
84  _fingerGhost2->SetAlpha(0.5f);
85  }
86  else
87  {
88  _fingerGhost1->SetAlpha(0.0f);
89  _fingerGhost2->SetAlpha(0.0f);
90  }
91 }
92 
93 
95 {
96  Vector2 pos = MathUtil::ScreenToWorld(screenCoordinates);
97  _fingerGhost1->SetPosition(pos);
98  _fingerGhost2->SetPosition(-pos);
99 
100  if (_mouseDown)
101  {
102  //move touch(es)
103  TouchList *tl = &TouchListener::GetTouchList();
104  if (tl->size() > 0)
105  {
106  (*tl)[0]->CurrentPoint = screenCoordinates;
107  if ( (*tl)[0]->MotionStartTime < 0.0f )
108  {
109  (*tl)[0]->MotionStartTime = theWorld.GetCurrentTimeSeconds();
110  }
111  }
112  if (tl->size() > 1)
113  {
114  Vector2 negCoordsVec = MathUtil::WorldToScreen(-pos);
115  Vec2i negCoords(negCoordsVec.X, negCoordsVec.Y);
116  (*tl)[1]->CurrentPoint = negCoords;
117  if ( (*tl)[1]->MotionStartTime < 0.0f )
118  {
119  (*tl)[1]->MotionStartTime = theWorld.GetCurrentTimeSeconds();
120  }
121 
122  Touch* t1 = (*tl)[0];
123  Touch* t2 = (*tl)[1];
124 
125  Vector2 start1(t1->StartingPoint);
126  Vector2 current1(t1->CurrentPoint);
127  Vector2 start2(t2->StartingPoint);
128  Vector2 current2(t2->CurrentPoint);
129 
130  Vector2 initialVector = start2 - start1;
131  Vector2 currentVector = current2 - current1;
132 
133  Vector2 initNorm = Vector2::Normalize(initialVector);
134  Vector2 currentNorm = Vector2::Normalize(currentVector);
135  float radiansRotated = acos(Vector2::Dot(initNorm, currentNorm));
136 
137  if (!_multiGestureOngoing)
138  {
139  Vector2 motion = current1 - start1;
140 
141  if (motion.LengthSquared() >= (MULTI_MIN_DISTANCE * MULTI_MIN_DISTANCE) )
142  {
143  _multiGestureOngoing = true;
144 
145  // figure out if it's a rotate or a pinch
146  if (radiansRotated > MULTI_ROTATE_ANGLE)
147  {
148  _gestureType = ROTATE;
149  }
150  else
151  {
152  _gestureType = PINCH;
153  }
154  }
155  }
156 
157  if (_multiGestureOngoing)
158  {
159  GestureData gd;
160  gd.Velocity = 0.0f; // don't want to store all the extra datums
161  // needed to actually calculate this
162 
163  if (_gestureType == ROTATE)
164  {
165  float cross = Vector2::Cross(initNorm, currentNorm);
166  if (cross > 0.0f)
167  {
168  radiansRotated = -radiansRotated;
169  }
170  gd.GestureMagnitude = radiansRotated;
171  theSwitchboard.Broadcast(new TypedMessage<GestureData>("MultiTouchRotate", gd));
172  }
173  else if (_gestureType == PINCH)
174  {
175  gd.GestureMagnitude = currentVector.Length() / initialVector.Length();
176  theSwitchboard.Broadcast(new TypedMessage<GestureData>("MultiTouchPinch", gd));
177  }
178  }
179  }
180  }
181 }
182 
183 void MobileSimulator::MouseDownEvent(Vec2i screenCoordinates, MouseButtonInput button)
184 {
185  _mouseDown = true;
186 
187  TouchList* tl = &TouchListener::GetTouchList();
188 
189  if (theInput.IsKeyDown(ANGEL_KEY_LEFTCONTROL) || theInput.IsKeyDown(ANGEL_KEY_RIGHTCONTROL))
190  {
191  // add the two touches
192  Touch* t = new Touch();
193  t->__platformTouch = NULL;
194  t->StartingPoint = screenCoordinates;
195  t->CurrentPoint = t->StartingPoint;
196  tl->push_back(t);
197  SendTouchNotifiers(t, TOUCH_START);
198 
199  t = new Touch();
200  t->__platformTouch = NULL;
201  Vector2 pos2 = MathUtil::WorldToScreen(_fingerGhost2->GetPosition());
202  t->StartingPoint = Vec2i(pos2.X, pos2.Y);
203  t->CurrentPoint = t->StartingPoint;
204  tl->push_back(t);
205  SendTouchNotifiers(t, TOUCH_START);
206  }
207  else
208  {
209  // just a single touch
210  Touch* t = new Touch();
211  t->__platformTouch = NULL;
212  t->StartingPoint = screenCoordinates;
213  t->CurrentPoint = t->StartingPoint;
214  tl->push_back(t);
215  SendTouchNotifiers(t, TOUCH_START);
216  }
217 }
218 
219 void MobileSimulator::MouseUpEvent(Vec2i screenCoordinates, MouseButtonInput button)
220 {
221  _multiGestureOngoing = false;
222  _gestureType = NONE;
223  _mouseDown = false;
224 
225  TouchList* tl = &TouchListener::GetTouchList();
226 
227  if (theInput.IsKeyDown(ANGEL_KEY_LEFTCONTROL) || theInput.IsKeyDown(ANGEL_KEY_RIGHTCONTROL))
228  {
229  TouchList::iterator it = tl->begin();
230  while (it != tl->end())
231  {
232  SendTouchNotifiers((*it), TOUCH_END);
233  delete (*it);
234  it = tl->erase(it);
235  }
236  }
237  else
238  {
239  // just a single touch, but we'll iterate anyway
240  TouchList::iterator it = tl->begin();
241  while (it != tl->end())
242  {
243  if ( (theWorld.GetCurrentTimeSeconds() - (*it)->MotionStartTime) < SWIPE_MAX_DURATION)
244  {
245  Vector2 start((*it)->StartingPoint.X, (*it)->StartingPoint.Y);
246  Vector2 end((*it)->CurrentPoint.X, (*it)->CurrentPoint.Y);
247  Vector2 motion = end - start;
248  if (motion.LengthSquared() >= (SWIPE_MIN_DISTANCE * SWIPE_MIN_DISTANCE))
249  {
250  float angle = MathUtil::ToDegrees(acos(Vector2::Dot(Vector2::UnitX, Vector2::Normalize(motion))));
251  if (motion.Y > 0.0f)
252  {
253  angle = 360.0f - angle;
254  }
255 
256  if ( (angle > 45.0f) && (angle <= 135.0f) )
257  {
258  // swipe up
259  theSwitchboard.Broadcast(new Message("MultiTouchSwipeUp"));
260  }
261  else if ( (angle > 135.0f) && (angle <= 225.0f) )
262  {
263  // swipe left
264  theSwitchboard.Broadcast(new Message("MultiTouchSwipeLeft"));
265  }
266  else if ( (angle > 225.0f) && (angle <= 315.0f) )
267  {
268  // swipe down
269  theSwitchboard.Broadcast(new Message("MultiTouchSwipeDown"));
270  }
271  else
272  {
273  // swipe right
274  theSwitchboard.Broadcast(new Message("MultiTouchSwipeRight"));
275  }
276  }
277  }
278  SendTouchNotifiers((*it), TOUCH_END);
279  delete (*it);
280  it = tl->erase(it);
281  }
282  }
283 }