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