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