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