Updated page-turn, blocks images; fixes to scroll-view demo; updated dali icon
[platform/core/uifw/dali-demo.git] / examples / blocks / blocks-example.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <sstream>
18 #include <iostream>
19 #include <vector>
20 #include <string>
21 #include <algorithm>
22
23 #include <boost/any.hpp>
24 #include <boost/function.hpp>
25 #include <dali/dali.h>
26 #include <dali-toolkit/dali-toolkit.h>
27 #include "../shared/view.h"
28
29 using namespace std;
30 using namespace Dali;
31 using namespace Dali::Toolkit;
32 using namespace DemoHelper;
33
34 namespace
35 {
36 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-blocks.jpg" );
37 const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
38 const char* APPLICATION_TITLE( "DALi Blocks" );
39 const char* BALL_IMAGE = DALI_IMAGE_DIR "blocks-ball.png";
40 const char* PADDLE_IMAGE = DALI_IMAGE_DIR "blocks-paddle.png";
41 const char* PADDLE_HANDLE_IMAGE = DALI_IMAGE_DIR "blocks-paddle-handle.png";
42
43 const char* BRICK_IMAGE_PATH[] =    { DALI_IMAGE_DIR "blocks-brick-1.png",
44                                       DALI_IMAGE_DIR "blocks-brick-2.png",
45                                       DALI_IMAGE_DIR "blocks-brick-3.png",
46                                       DALI_IMAGE_DIR "blocks-brick-4.png" };
47
48 const int TOTAL_BRICKS(4);                                                  ///< Total bricks in game.
49 const Vector3 ICON_SIZE(100.0f, 100.0f, 0.0f);
50
51 const float SCREEN_MARGIN = 10.0f;                                          ///< Margin indentation around screen
52 const Vector3 MENU_BUTTON_SIZE = Vector3(0.15f, 0.05f, 1.0f);               ///< Standard Menu Buttons.
53
54 const float MAX_ANIMATION_DURATION = 60.0f;                                 ///< 60 seconds animations. Long enough for ball to hit an obstacle.
55 const float BALL_VELOCITY = 300.0f;                                         ///< Ball velocity in pixels/second.
56 const float MAX_VELOCITY = 500.0f;                                          ///< Max. velocity in pixels/second.
57 const Vector3 PADDLE_COLLISION_MARGIN(0.0f, 0.0f, 0.0f);                    ///< Collision margin for ball-paddle detection.
58 const Vector3 BRICK_COLLISION_MARGIN(0.0f, 0.0f, 0.0f);                     ///< Collision margin for ball-brick detection.
59 const Vector3 INITIAL_BALL_DIRECTION(1.0f, 1.0f, 0.0f);                     ///< Initial ball direction.
60
61 const std::string WOBBLE_PROPERTY_NAME("wobble-property");                  ///< Wobble property name.
62 const std::string COLLISION_PROPERTY_NAME("collision-property");            ///< Collision property name.
63
64 const Vector2 BRICK_SIZE(0.1f, 0.05f );                                     ///< Brick size relative to width of stage.
65 const Vector2 BALL_SIZE( 0.05f, 0.05f );                                    ///< Ball size relative to width of stage.
66 const Vector2 PADDLE_SIZE( 0.2f, 0.05f );                                   ///< Paddle size relative to width of stage.
67 const Vector2 PADDLE_HANDLE_SIZE( 0.3f, 0.3f );                             ///< Paddle handle size relative to width of stage.
68 const Vector2 BALL_START_POSITION(0.5f, 0.8f);                              ///< Ball start position relative to stage size.
69 const Vector2 PADDLE_START_POSITION(0.5f, 0.9f);                            ///< Paddler start position relative to stage size.
70 const Vector2 PADDLE_HIT_MARGIN( 0.1, 0.15f );                              ///< Extra hit Area for Paddle when touching.
71
72 const int TOTAL_LIVES(3);                                                   ///< Total lives in game before it's game over!
73 const int TOTAL_LEVELS(3);                                                  ///< 3 Levels total, then repeats.
74
75 // constraints ////////////////////////////////////////////////////////////////
76
77 /**
78  * CollisionConstraint generates a collision vector
79  * between two actors a and b, assuming they're rectangular
80  * based on their size.
81  */
82 struct CollisionConstraint
83 {
84   /**
85    * Collision Constraint constructor
86    * The adjust (optional) parameter can be used to add a margin
87    * to the actors. A +ve size will result in larger collisions,
88    * while a -ve size will result in tighter collisions.
89    *
90    * @param[in] adjust (optional) Adjusts the rectangular size detection
91    */
92   CollisionConstraint(Vector3 adjust = Vector3::ZERO)
93   : mAdjust(adjust)
94   {
95   }
96
97   /**
98    * Generates collision vector indicating whether Actor's A and B
99    * have overlapped eachother, and the relative position of Actor B to A.
100    *
101    * @param[in] current The current collision-property (ignored)
102    * @param[in] propertyA Actor A's Position property.
103    * @param[in] propertyB Actor B's Position property.
104    * @param[in] propertySizeA Actor A's Size property.
105    * @param[in] propertySizeB Actor B's Size property.
106    * @return The collision vector is returned.
107    */
108   Vector3 operator()(const Vector3& current,
109                      const PropertyInput& propertyA,
110                      const PropertyInput& propertyB,
111                      const PropertyInput& propertySizeA,
112                      const PropertyInput& propertySizeB)
113   {
114     const Vector3& a = propertyA.GetVector3();
115     const Vector3& b = propertyB.GetVector3();
116     const Vector3& sizeA = propertySizeA.GetVector3();
117     const Vector3& sizeB = propertySizeB.GetVector3();
118     const Vector3 sizeComb = (sizeA + sizeB + mAdjust) * 0.5f;
119
120     // get collision relative to a.
121     Vector3 delta = b - a;
122
123     // Check if not overlapping Actors.
124     if( (fabsf(delta.x) > sizeComb.width) ||
125         (fabsf(delta.y) > sizeComb.height) )
126     {
127       delta = Vector3::ZERO; // not overlapping
128     }
129
130     return delta; // overlapping, return overlap vector relative to actor a.
131   }
132
133   const Vector3 mAdjust;            ///< Size Adjustment value
134 };
135
136 /**
137  * CollisionCircleRectangleConstraint generates a collision vector
138  * between two actors a (circle) and b (rectangle)
139  */
140 struct CollisionCircleRectangleConstraint
141 {
142   /**
143    * Collision Constraint constructor
144    * The adjust (optional) parameter can be used to add a margin
145    * to the actors. A +ve size will result in larger collisions,
146    * while a -ve size will result in tighter collisions.
147    *
148    * @param[in] adjustPosition (optional) Adjusts the position offset of detection
149    * @param[in] adjustSize (optional) Adjusts the rectangular size of detection
150    */
151   CollisionCircleRectangleConstraint(Vector3 adjustPosition = Vector3::ZERO,
152                                      Vector3 adjustSize = Vector3::ZERO)
153   : mAdjustPosition(adjustPosition),
154     mAdjustSize(adjustSize)
155   {
156   }
157
158   /**
159    * Generates collision vector indicating whether Actor's A and B
160    * have overlapped eachother, and the relative position of Actor B to A.
161    *
162    * @param[in] current The current collision-property (ignored)
163    * @param[in] propertyA Actor A's Position property.
164    * @param[in] propertyB Actor B's Position property.
165    * @param[in] propertySizeA Actor A's Size property.
166    * @param[in] propertySizeB Actor B's Size property.
167    * @return The collision vector is returned.
168    */
169   Vector3 operator()(const Vector3& current,
170                      const PropertyInput& propertyA,
171                      const PropertyInput& propertyB,
172                      const PropertyInput& propertySizeA,
173                      const PropertyInput& propertySizeB)
174   {
175     const Vector3& a = propertyA.GetVector3();
176     const Vector3 b = propertyB.GetVector3() + mAdjustPosition;
177     const Vector3& sizeA = propertySizeA.GetVector3();
178     const Vector3& sizeB = propertySizeB.GetVector3();
179     const Vector3 sizeA2 = sizeA * 0.5f; // circle radius
180     const Vector3 sizeB2 = (sizeB + mAdjustSize) * 0.5f; // rectangle half rectangle.
181
182     // get collision relative to a (rectangle).
183     Vector3 delta = a - b;
184
185     // reduce rectangle to 0.
186     if (delta.x > sizeB2.x)
187     {
188       delta.x -= sizeB2.x;
189     }
190     else if (delta.x < -sizeB2.x)
191     {
192       delta.x += sizeB2.x;
193     }
194     else
195     {
196       delta.x = 0;
197     }
198
199     if (delta.y > sizeB2.y)
200     {
201       delta.y -= sizeB2.y;
202     }
203     else if (delta.y < -sizeB2.y)
204     {
205       delta.y += sizeB2.y;
206     }
207     else
208     {
209       delta.y = 0;
210     }
211
212     // now calculate collision vector vs origin. (assume A is a circle, not ellipse)
213     if(delta.Length() < sizeA2.x)
214     {
215       delta.Normalize();
216       return delta;
217     }
218
219     return Vector3::ZERO;
220   }
221
222   const Vector3 mAdjustPosition;            ///< Position Adjustment value
223   const Vector3 mAdjustSize;                ///< Size Adjustment value
224 };
225
226 /**
227  * WobbleConstraint generates a decaying sinusoidial rotation.
228  * The result when applied to an Actor, is the Actor rotating left/right
229  * initially a large amount (deviation degrees, when wobble property is 0.0f)
230  * then eventually coming to a stop (once wobble property reaches 1.0f)
231  */
232 struct WobbleConstraint
233 {
234   /**
235    * Wobble Constraint constructor
236    * Generates a sinusoidial rotation that starts with
237    * high amplitude (deviation), and then decays to zero over input 0.0f to 1.0f
238    *
239    * @param[in] deviation The max. deviation of wobble effect in degrees.
240    */
241   WobbleConstraint(float deviation)
242   : mDeviation(Radian(Degree(deviation)))
243   {
244
245   }
246
247   /**
248    * @param[in] current The current rotation property (ignored)
249    * @param[in] propertyWobble The wobble property (value from 0.0f to 1.0f)
250    * @return The rotation (quaternion) is generated.
251    */
252   Quaternion operator()(const Quaternion& current,
253                      const PropertyInput& propertyWobble)
254   {
255     const float& wobble = propertyWobble.GetFloat();
256
257     float f = sinf(wobble * 10.0f) * (1.0f-wobble);
258
259     Quaternion q(mDeviation * f, Vector3::ZAXIS);
260
261     return q;
262   }
263
264   const float mDeviation;           ///< Deviation factor in radians.
265 };
266
267 } // unnamed namespace
268
269 /**
270  * This example shows how to use PropertyNotifications
271  */
272 class ExampleController : public ConnectionTracker
273 {
274 public:
275
276   /**
277    * Constructor
278    * @param application Application class, stored as reference
279    */
280   ExampleController( Application& application )
281   : mApplication( application ),
282     mView()
283   {
284     // Connect to the Application's Init and orientation changed signal
285     mApplication.InitSignal().Connect(this, &ExampleController::Create);
286   }
287
288   /**
289    * This method gets called once the main loop of application is up and running
290    * @param[in] application Reference to the application instance
291    */
292   void Create(Application& application)
293   {
294     Stage::GetCurrent().KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
295
296     // Creates a default view with a default tool bar.
297     // The view is added to the stage.
298     Toolkit::ToolBar toolBar;
299     mContentLayer = DemoHelper::CreateView( application,
300                                             mView,
301                                             toolBar,
302                                             BACKGROUND_IMAGE,
303                                             TOOLBAR_IMAGE,
304                                             APPLICATION_TITLE );
305
306     // Add an extra space on the right to center the title text.
307     toolBar.AddControl( Actor::New(), DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight );
308
309     // Create the content layer, which is where game actors appear.
310     AddContentLayer();
311   }
312
313 private:
314
315   /**
316    * Adds a new layer to the stage, containing game actors.
317    */
318   void AddContentLayer()
319   {
320     Stage stage = Stage::GetCurrent();
321     const Vector3 stageSize(stage.GetSize());
322
323     // Ball setup
324     mBallStartPosition = stageSize * Vector3( BALL_START_POSITION );
325     mBall = CreateImage(BALL_IMAGE);
326     mBall.SetPosition( mBallStartPosition );
327     mBall.SetSize( BALL_SIZE * stageSize.width );
328     mContentLayer.Add(mBall);
329     mBallVelocity = Vector3::ZERO;
330
331     // Paddle setup
332     mPaddleHitMargin = Vector2(stageSize) * PADDLE_HIT_MARGIN;
333     mPaddle = Actor::New();
334     mPaddleHandle = CreateImage(PADDLE_HANDLE_IMAGE);
335     mPaddleImage = CreateImage(PADDLE_IMAGE);
336     mPaddle.Add( mPaddleHandle );
337     mPaddle.Add( mPaddleImage );
338     mPaddleHandle.SetParentOrigin( ParentOrigin::TOP_CENTER );
339     mPaddleHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER );
340     mPaddleHandle.SetPosition( 0.0f, stageSize.width * 0.0125f );
341     mPaddleImage.SetParentOrigin( ParentOrigin::TOP_CENTER );
342     mPaddleImage.SetAnchorPoint( AnchorPoint::TOP_CENTER );
343     mPaddle.SetParentOrigin( ParentOrigin::TOP_LEFT );
344     mPaddle.SetAnchorPoint( AnchorPoint::CENTER );
345     mPaddleFullSize = PADDLE_SIZE * stageSize.width;
346     mPaddle.SetSize( mPaddleFullSize + mPaddleHitMargin );
347     mPaddleHandle.SetSize( PADDLE_HANDLE_SIZE * stageSize.width );
348     mPaddleImage.SetSize( mPaddleFullSize );
349
350     mWobbleProperty = mPaddle.RegisterProperty(WOBBLE_PROPERTY_NAME, 0.0f);
351     Constraint wobbleConstraint = Constraint::New<Quaternion>( Actor::ROTATION,
352                                                     LocalSource(mWobbleProperty),
353                                                     WobbleConstraint(10.0f));
354     mPaddle.ApplyConstraint(wobbleConstraint);
355
356     mPaddle.SetPosition( stageSize * Vector3( PADDLE_START_POSITION ) );
357     mContentLayer.Add(mPaddle);
358     mPaddle.TouchedSignal().Connect(this, &ExampleController::OnTouchPaddle);
359     mContentLayer.TouchedSignal().Connect(this, &ExampleController::OnTouchLayer);
360
361     const float margin(BALL_SIZE.width * stageSize.width * 0.5f);
362
363     // Set up notifications for ball's collisions against walls.
364     PropertyNotification leftNotification = mBall.AddPropertyNotification( Actor::POSITION_X, LessThanCondition(margin) );
365     leftNotification.NotifySignal().Connect( this, &ExampleController::OnHitLeftWall );
366
367     PropertyNotification rightNotification = mBall.AddPropertyNotification( Actor::POSITION_X, GreaterThanCondition(stageSize.width - margin) );
368     rightNotification.NotifySignal().Connect( this, &ExampleController::OnHitRightWall );
369
370     PropertyNotification topNotification = mBall.AddPropertyNotification( Actor::POSITION_Y, LessThanCondition(margin) );
371     topNotification.NotifySignal().Connect( this, &ExampleController::OnHitTopWall );
372
373     PropertyNotification bottomNotification = mBall.AddPropertyNotification( Actor::POSITION_Y, GreaterThanCondition(stageSize.height + margin) );
374     bottomNotification.NotifySignal().Connect( this, &ExampleController::OnHitBottomWall );
375
376     // Set up notification for ball colliding against paddle.
377     Actor delegate = Actor::New();
378     stage.Add(delegate);
379     Property::Index property = delegate.RegisterProperty(COLLISION_PROPERTY_NAME, Vector3::ZERO);
380     Constraint constraint = Constraint::New<Vector3>( property,
381                                                     Source(mBall, Actor::POSITION),
382                                                     Source(mPaddle, Actor::POSITION),
383                                                     Source(mBall, Actor::SIZE),
384                                                     Source(mPaddle, Actor::SIZE),
385                                                     CollisionCircleRectangleConstraint( -Vector3(0.0f, mPaddleHitMargin.height * 0.575f, 0.0f),-Vector3(mPaddleHitMargin) ));
386     delegate.ApplyConstraint(constraint);
387
388     PropertyNotification paddleNotification = delegate.AddPropertyNotification( property, GreaterThanCondition(0.0f) );
389     paddleNotification.NotifySignal().Connect( this, &ExampleController::OnHitPaddle );
390
391     RestartGame();
392   }
393
394   /**
395    * Restarts Game
396    * Resets Lives count and other stats, and loads level
397    */
398   void RestartGame()
399   {
400     mLives = TOTAL_LIVES;
401     mLevel = 0;
402     mBall.SetPosition( mBallStartPosition );
403     mBallVelocity = Vector3::ZERO;
404     mPaddle.SetSize( mPaddleFullSize + mPaddleHitMargin );
405     mPaddleImage.SetSize( mPaddleFullSize );
406
407     LoadLevel(mLevel);
408   }
409
410   /**
411    * Loads level
412    * All existing level content is removed, and new bricks
413    * are added.
414    * @param[in] level Level index to load.
415    */
416   void LoadLevel(int level)
417   {
418     if(mLevelContainer && mLevelContainer.GetParent() == mContentLayer)
419     {
420       mContentLayer.Remove( mLevelContainer );
421     }
422
423     mLevelContainer = Actor::New();
424     mLevelContainer.SetAnchorPoint( AnchorPoint::CENTER );
425     mLevelContainer.SetParentOrigin( ParentOrigin::CENTER );
426     mLevelContainer.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
427     mContentLayer.Add( mLevelContainer );
428
429     mBrickCount = 0;
430
431     switch(level%TOTAL_LEVELS)
432     {
433       case 0:
434       {
435         GenerateLevel0();
436         break;
437       }
438       case 1:
439       {
440         GenerateLevel1();
441         break;
442       }
443       case 2:
444       {
445         GenerateLevel2();
446         break;
447       }
448       default:
449       {
450         break;
451       }
452     } // end switch
453   }
454
455   /**
456    * Generates level 0
457    */
458   void GenerateLevel0()
459   {
460     Vector2 stageSize(Stage::GetCurrent().GetSize());
461     const Vector2 brickSize(BRICK_SIZE * stageSize.width);
462
463     const int columns = (0.85f * stageSize.width) / brickSize.width; // 85 percent of the width of the screen covered with bricks.
464     const int rows = (0.3f * stageSize.height) / brickSize.height;   // 30 percent of the height of the screen covered with bricks.
465     const Vector2 offset( (stageSize.x - (columns * brickSize.width)) * 0.5f,
466                            stageSize.y * 0.125f );
467
468     for(int j = 0; j < rows; j++)
469     {
470       for(int i = 0; i < columns; i++)
471       {
472         Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), j % TOTAL_BRICKS );
473         mLevelContainer.Add(brick);
474         mBrickCount++;
475       }
476     }
477   }
478
479   /**
480    * Generates level 1
481    */
482   void GenerateLevel1()
483   {
484     Vector2 stageSize(Stage::GetCurrent().GetSize());
485     const Vector2 brickSize(BRICK_SIZE * stageSize.width);
486
487     const int columns = (0.85f * stageSize.width) / brickSize.width; // 85 percent of the width of the screen covered with bricks.
488     const int rows = (0.3f * stageSize.height) / brickSize.height;   // 30 percent of the height of the screen covered with bricks.
489     const Vector2 offset( (stageSize.x - (columns * brickSize.width)) * 0.5f,
490                            stageSize.y * 0.125f );
491
492     for(int j = 0; j < rows; j++)
493     {
494       for(int i = 0; i < columns; i++)
495       {
496         int i2 = columns - i - 1;
497         int j2 = rows - j - 1;
498         int brickIndex = std::min( std::min(i, j), std::min(i2, j2) ) % TOTAL_BRICKS;
499
500         Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), brickIndex );
501
502         mLevelContainer.Add(brick);
503         mBrickCount++;
504       }
505     }
506   }
507
508   /**
509    * Generates level 2
510    */
511   void GenerateLevel2()
512   {
513     Vector2 stageSize(Stage::GetCurrent().GetSize());
514     const Vector2 brickSize(BRICK_SIZE * stageSize.width);
515
516     const int columns = (0.85f * stageSize.width) / brickSize.width; // 85 percent of the width of the screen covered with bricks.
517     const int rows = (0.3f * stageSize.height) / brickSize.height;   // 30 percent of the height of the screen covered with bricks.
518     const Vector2 offset( (stageSize.x - (columns * brickSize.width)) * 0.5f,
519                            stageSize.y * 0.125f );
520
521     // lays down bricks in a spiral formation starting at i,j = (0,0) top left corner
522     // travelling right di,dj = (1,0) initially
523     int i = 0;
524     int j = 0;
525     int di = 1;
526     int dj = 0;
527
528     // contracting boundaries
529     int left = 0;
530     int right = columns - 1;
531     int top = 2;
532     int bottom = rows - 1;
533
534     // length of current line. we stop laying down bricks when the length is 1 brick or less.
535     int length = 0;
536     while(true)
537     {
538       Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), 0 );
539       mLevelContainer.Add(brick);
540       i+=di;
541       j+=dj;
542       bool turn(false);
543       if((i==right) && (di==1))
544       {
545         right -= 2;
546         turn = true;
547       }
548       if((j==bottom) && (dj==1))
549       {
550         bottom -= 2;
551         turn = true;
552       }
553       if((i==left) && (di==-1))
554       {
555         left += 2;
556         turn = true;
557       }
558       if((j==top) && (dj==-1))
559       {
560         top += 2;
561         turn = true;
562       }
563       if(turn)
564       {
565         // turn 90 degrees clockwise.
566         swap(di, dj);
567         di = -di;
568         if (length<=1)
569         {
570           break;
571         }
572         length = 0;
573       }
574       length++;
575       mBrickCount++;
576     }
577   }
578
579
580   /**
581    * Creates a brick at a specified position on the stage
582    * @param[in] position the position for the brick
583    * @param[in] type the type of brick
584    * @return The Brick Actor is returned.
585    */
586   Actor CreateBrick( const Vector2& position, int type )
587   {
588     Vector2 stageSize(Stage::GetCurrent().GetSize());
589     const Vector2 brickSize(BRICK_SIZE * Vector2(stageSize.x, stageSize.x));
590
591     ImageAttributes attr;
592     attr.SetSize( 128, 64 );
593     attr.SetScalingMode( ImageAttributes::ScaleToFill );
594     Image img = Image::New(BRICK_IMAGE_PATH[type], attr);
595     ImageActor brick = ImageActor::New(img);
596     brick.SetParentOrigin(ParentOrigin::TOP_LEFT);
597     brick.SetAnchorPoint(AnchorPoint::CENTER);
598     brick.SetSize( brickSize );
599     brick.SetPosition( Vector3( position ) );
600
601     // Add a constraint on the brick between it and the ball generating a collision-property
602     Property::Index property = brick.RegisterProperty(COLLISION_PROPERTY_NAME, Vector3::ZERO);
603     Constraint constraint = Constraint::New<Vector3>( property,
604                                                     Source(mBall, Actor::POSITION),
605                                                     Source(brick, Actor::POSITION),
606                                                     Source(mBall, Actor::SIZE),
607                                                     Source(brick, Actor::SIZE),
608                                                     CollisionCircleRectangleConstraint(BRICK_COLLISION_MARGIN));
609     brick.ApplyConstraint(constraint);
610
611     // Now add a notification on this collision-property
612
613     PropertyNotification brickNotification = brick.AddPropertyNotification( property, GreaterThanCondition(0.0f) );
614     brickNotification.NotifySignal().Connect( this, &ExampleController::OnHitBrick );
615
616     return brick;
617   }
618
619   /**
620    * Creates an Image (Helper)
621    *
622    * @param[in] filename the path of the image.
623    */
624   ImageActor CreateImage(const std::string& filename)
625   {
626     Image img = Image::New(filename);
627     ImageActor actor = ImageActor::New(img);
628     actor.SetParentOrigin(ParentOrigin::TOP_LEFT);
629     actor.SetAnchorPoint(AnchorPoint::CENTER);
630     return actor;
631   }
632
633   /**
634    * Continue animation (based on current velocity)
635    */
636   void ContinueAnimation()
637   {
638     if(mBallAnimation)
639     {
640       mBallAnimation.Clear();
641     }
642
643     mBallAnimation = Animation::New(MAX_ANIMATION_DURATION);
644     mBallAnimation.AnimateBy( Property( mBall, Actor::POSITION ), mBallVelocity * MAX_ANIMATION_DURATION);
645     mBallAnimation.Play();
646   }
647
648   /**
649    * Signal invoked whenever user touches the Paddle.
650    * @param[in] actor The actor touched
651    * @param[in] event The touch event
652    */
653   bool OnTouchPaddle(Actor actor, const TouchEvent& event)
654   {
655     if(event.GetPointCount()>0)
656     {
657       const TouchPoint& point = event.GetPoint(0);
658       if(point.state==TouchPoint::Down) // Commence dragging
659       {
660         // Get point where user touched paddle (relative to paddle's center)
661         mRelativeDragPoint = Vector3(point.screen.x, point.screen.y, 0.0f);
662         mRelativeDragPoint -= actor.GetCurrentPosition();
663
664         mDragActor = actor;
665         mDragAnimation = Animation::New(0.25f);
666         mDragAnimation.AnimateTo( Property(mDragActor, Actor::SCALE), Vector3(1.1f, 1.1f, 1.0f), AlphaFunctions::EaseOut);
667         mDragAnimation.AnimateTo( Property(mPaddleHandle, Actor::COLOR), Vector4(1.0f, 1.0f, 1.0f, 0.0f), AlphaFunctions::EaseOut);
668         mDragAnimation.Play();
669       }
670     }
671     return false;
672   }
673
674   /**
675    * Signal invoked whenever user touches anywhere on the screen.
676    * @param[in] actor The actor touched
677    * @param[in] event The touch event
678    */
679   bool OnTouchLayer(Actor actor, const TouchEvent& event)
680   {
681     if(event.GetPointCount()>0)
682     {
683       const TouchPoint& point = event.GetPoint(0);
684       if(mDragActor)
685       {
686         Vector3 position(point.screen.x, point.screen.y, 0.0f);
687         mPaddle.SetPosition( position - mRelativeDragPoint );
688
689         if(point.state==TouchPoint::Up) // Stop dragging
690         {
691           mDragAnimation = Animation::New(0.25f);
692           mDragAnimation.AnimateTo( Property(mDragActor, Actor::SCALE), Vector3(1.0f, 1.0f, 1.0f), AlphaFunctions::EaseIn);
693           mDragAnimation.AnimateTo( Property(mPaddleHandle, Actor::COLOR), Vector4(1.0f, 1.0f, 1.0f, 1.0f), AlphaFunctions::EaseOut);
694           mDragAnimation.Play();
695           mDragActor.Reset();
696         }
697       }
698     }
699     return false;
700   }
701
702   /**
703    * Notification: Ball hit left wall
704    * @param source The notification
705    */
706   void OnHitLeftWall(PropertyNotification& source)
707   {
708     mBallVelocity.x = fabsf(mBallVelocity.x);
709     ContinueAnimation();
710   }
711
712   /**
713    * Notification: Ball hit right wall
714    * @param source The notification
715    */
716   void OnHitRightWall(PropertyNotification& source)
717   {
718     mBallVelocity.x = -fabsf(mBallVelocity.x);
719     ContinueAnimation();
720   }
721
722   /**
723    * Notification: Ball hit top wall
724    * @param source The notification
725    */
726   void OnHitTopWall(PropertyNotification& source)
727   {
728     mBallVelocity.y = fabsf(mBallVelocity.y);
729     ContinueAnimation();
730   }
731
732   /**
733    * Notification: Ball hit bottom wall
734    * @param source The notification
735    */
736   void OnHitBottomWall(PropertyNotification& source)
737   {
738     if(mBallAnimation)
739     {
740       mBallAnimation.Clear();
741     }
742
743     if(mLives>0)
744     {
745       mLives--;
746       const float f(static_cast<float>(mLives) / TOTAL_LIVES);
747       mBallVelocity = Vector3::ZERO;
748
749       Animation shrink = Animation::New(0.5f);
750       shrink.AnimateTo( Property(mPaddle, Actor::SIZE_WIDTH), mPaddleFullSize.x * f + mPaddleHitMargin.x);
751       shrink.AnimateTo( Property(mPaddleImage, Actor::SIZE_WIDTH), mPaddleFullSize.x * f );
752
753       shrink.FinishedSignal().Connect( this, &ExampleController::OnPaddleShrunk );
754       shrink.Play();
755     }
756   }
757
758   /**
759    * Paddle Shrink Animation complete.
760    * @param[in] source The animation responsible for shrinking the paddle.
761    */
762   void OnPaddleShrunk( Animation &source )
763   {
764     // Reposition Ball in start position, and make ball appear.
765     mBall.SetPosition( mBallStartPosition );
766     mBall.SetColor( Vector4(1.0f, 1.0f, 1.0f, 0.1f) );
767     Animation appear = Animation::New(0.5f);
768     appear.AnimateTo( Property(mBall, Actor::COLOR), Vector4(1.0f, 1.0f, 1.0f, 1.0f) );
769     appear.Play();
770
771     if(!mLives)
772     {
773       RestartGame();
774     }
775   }
776
777   /**
778    * Notification: Ball hit paddle
779    * @param source The notification
780    */
781   void OnHitPaddle(PropertyNotification& source)
782   {
783     Actor delegate = Actor::DownCast(source.GetTarget());
784     Vector3 collisionVector = delegate.GetProperty<Vector3>(source.GetTargetProperty());
785     Vector3 ballRelativePosition(mBall.GetCurrentPosition() - mPaddle.GetCurrentPosition());
786     ballRelativePosition.Normalize();
787
788     collisionVector.x += ballRelativePosition.x * 0.5f;
789
790     if(mBallVelocity.LengthSquared() < Math::MACHINE_EPSILON_1)
791     {
792       mBallVelocity += collisionVector * BALL_VELOCITY;
793     }
794     else
795     {
796       const float normalVelocity = fabsf(mBallVelocity.Dot(collisionVector));
797       mBallVelocity += collisionVector * normalVelocity * 2.0f;
798       const float currentSpeed = mBallVelocity.Length();
799       const float limitedSpeed = std::min( currentSpeed, MAX_VELOCITY );
800       mBallVelocity = mBallVelocity * limitedSpeed / currentSpeed;
801     }
802
803     ContinueAnimation();
804
805     // wobble paddle
806     mWobbleAnimation = Animation::New(0.5f);
807     mWobbleAnimation.AnimateTo( Property( mPaddle, mWobbleProperty ), 1.0f );
808     mWobbleAnimation.Play();
809     mPaddle.SetProperty(mWobbleProperty, 0.0f);
810   }
811
812   /**
813    * Notification: Ball hit brick
814    * @param source The notification
815    */
816   void OnHitBrick(PropertyNotification& source)
817   {
818     Actor brick = Actor::DownCast(source.GetTarget());
819     Vector3 collisionVector = brick.GetProperty<Vector3>(source.GetTargetProperty());
820
821     const float normalVelocity = fabsf(mBallVelocity.Dot(collisionVector));
822     mBallVelocity += collisionVector * normalVelocity * 2.0f;
823     const float currentSpeed = mBallVelocity.Length();
824     const float limitedSpeed = std::min( currentSpeed, MAX_VELOCITY );
825     mBallVelocity = mBallVelocity * limitedSpeed / currentSpeed;
826
827     ContinueAnimation();
828
829     // remove collision-constraint and notification.
830     brick.RemovePropertyNotification(source);
831     brick.RemoveConstraints();
832
833     // fade brick (destroy)
834     Animation destroyAnimation = Animation::New(0.5f);
835     destroyAnimation.AnimateTo( Property( brick, Actor::COLOR_ALPHA ), 0.0f, AlphaFunctions::EaseIn );
836     destroyAnimation.Play();
837     destroyAnimation.FinishedSignal().Connect( this, &ExampleController::OnBrickDestroyed );
838     mDestroyAnimationMap[destroyAnimation] = brick;
839   }
840
841   /**
842    * Brick Destruction Animation complete.
843    * @param[in] source The animation responsible for destroying the brick
844    */
845   void OnBrickDestroyed( Animation& source )
846   {
847     // Remove brick from stage, it's constraint and property notification should also remove themselves.
848     Actor brick = mDestroyAnimationMap[source];
849     mDestroyAnimationMap.erase(source);
850     brick.GetParent().Remove(brick);
851     mBrickCount--;
852
853     if(!mBrickCount)
854     {
855       mLevel++;
856       LoadLevel(mLevel);
857     }
858   }
859
860   /**
861    * Main key event handler
862    */
863   void OnKeyEvent(const KeyEvent& event)
864   {
865     if(event.state == KeyEvent::Down)
866     {
867       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
868       {
869         mApplication.Quit();
870       }
871     }
872   }
873
874 private:
875
876   Application& mApplication;                            ///< Application instance
877   Toolkit::View mView;                                  ///< The View instance.
878   Layer mContentLayer;                                  ///< The content layer (contains game actors)
879   ImageActor mBall;                                     ///< The Moving ball image.
880   Vector3 mBallStartPosition;                           ///< Ball Start position
881   Vector3 mBallVelocity;                                ///< Ball's current direction.
882   Animation mBallAnimation;                             ///< Ball's animation
883   Actor mPaddle;                                        ///< The paddle including hit area.
884   ImageActor mPaddleImage;                              ///< The paddle's image.
885   ImageActor mPaddleHandle;                             ///< The paddle's handle (where the user touches)
886   Vector2 mPaddleHitMargin;                             ///< The paddle hit margin.
887   Animation mWobbleAnimation;                           ///< Paddle's animation when hit (wobbles)
888   Property::Index mWobbleProperty;                      ///< The wobble property (generated from animation)
889   Actor mLevelContainer;                                ///< The level container (contains bricks)
890
891   // actor - dragging functionality
892
893   Animation mDragAnimation;                             ///< Animation for dragging. (grows - affects ACTOR::SCALE)
894   Actor mDragActor;                                     ///< The actor which is being dragged (if any)
895   Vector3 mRelativeDragPoint;                           ///< The point the user touched, relative to the actor.
896   std::map<Animation, Actor> mDestroyAnimationMap;      ///< Keep track of which actors are to be destroyed.
897   Vector2 mPaddleFullSize;                              ///< Initial 100% size of the paddle.
898   int mLevel;                                           ///< Current level
899   int mLives;                                           ///< Total lives.
900   int mBrickCount;                                      ///< Total bricks on screen.
901 };
902
903 void RunTest(Application& app)
904 {
905   ExampleController test(app);
906
907   app.MainLoop();
908 }
909
910 int main(int argc, char **argv)
911 {
912   Application app = Application::New(&argc, &argv);
913
914   RunTest(app);
915
916   return 0;
917 }