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