2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
30 using namespace Dali::Toolkit;
31 using namespace DemoHelper;
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";
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" };
47 const int TOTAL_BRICKS(4); ///< Total bricks in game.
48 const Vector3 ICON_SIZE(100.0f, 100.0f, 0.0f);
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.
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.
60 const std::string WOBBLE_PROPERTY_NAME("wobbleProperty"); ///< Wobble property name.
61 const std::string COLLISION_PROPERTY_NAME("collisionProperty"); ///< Collision property name.
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.
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.
74 // constraints ////////////////////////////////////////////////////////////////
77 * CollisionCircleRectangleConstraint generates a collision vector
78 * between two actors a (circle) and b (rectangle)
80 struct CollisionCircleRectangleConstraint
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.
88 * @param[in] adjustPosition (optional) Adjusts the position offset of detection
89 * @param[in] adjustSize (optional) Adjusts the rectangular size of detection
91 CollisionCircleRectangleConstraint(Vector3 adjustPosition = Vector3::ZERO,
92 Vector3 adjustSize = Vector3::ZERO)
93 : mAdjustPosition(adjustPosition),
94 mAdjustSize(adjustSize)
99 * Generates collision vector indicating whether Actor's A and B
100 * have overlapped eachother, and the relative position of Actor B to A.
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.
110 void operator()( Vector3& current, const PropertyInputContainer& inputs )
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.
119 // get collision relative to a (rectangle).
120 Vector3 delta = a - b;
122 // reduce rectangle to 0.
123 if (delta.x > sizeB2.x)
127 else if (delta.x < -sizeB2.x)
136 if (delta.y > sizeB2.y)
140 else if (delta.y < -sizeB2.y)
149 // now calculate collision vector vs origin. (assume A is a circle, not ellipse)
150 if(delta.Length() < sizeA2.x)
157 current = Vector3::ZERO;
161 const Vector3 mAdjustPosition; ///< Position Adjustment value
162 const Vector3 mAdjustSize; ///< Size Adjustment value
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)
171 struct WobbleConstraint
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
178 * @param[in] deviation The max. deviation of wobble effect in degrees.
180 WobbleConstraint( Degree deviation )
181 : mDeviation( deviation )
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.
191 void operator()( Quaternion& current, const PropertyInputContainer& inputs )
193 const float& wobble = inputs[0]->GetFloat();
195 float f = sinf(wobble * 10.0f) * (1.0f-wobble);
197 current = Quaternion(mDeviation * f, Vector3::ZAXIS);
200 Radian mDeviation; ///< Deviation factor in radians.
203 } // unnamed namespace
206 * This example shows how to use PropertyNotifications
208 class ExampleController : public ConnectionTracker
214 * @param application Application class, stored as reference
216 ExampleController( Application& application )
217 : mApplication( application ),
221 mBallStartPosition(),
229 mWobbleProperty( Property::INVALID_INDEX ),
234 mRelativeDragPoint(),
235 mDestroyAnimationMap(),
238 mLives( TOTAL_LIVES ),
242 // Connect to the Application's Init and orientation changed signal
243 mApplication.InitSignal().Connect(this, &ExampleController::Create);
247 * This method gets called once the main loop of application is up and running
248 * @param[in] application Reference to the application instance
250 void Create(Application& application)
252 Stage::GetCurrent().KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
254 // Hide the indicator bar
255 application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
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,
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 );
270 // Create the content layer, which is where game actors appear.
277 * Adds a new layer to the stage, containing game actors.
279 void AddContentLayer()
281 Stage stage = Stage::GetCurrent();
282 const Vector3 stageSize(stage.GetSize());
285 mBallStartPosition = stageSize * Vector3( BALL_START_POSITION );
286 mBall = CreateImage(BALL_IMAGE);
287 mBall.SetPosition( mBallStartPosition );
288 mBall.SetSize( BALL_SIZE * stageSize.width );
289 mContentLayer.Add(mBall);
290 mBallVelocity = Vector3::ZERO;
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.SetParentOrigin( ParentOrigin::TOP_CENTER );
300 mPaddleHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER );
301 mPaddleHandle.SetPosition( 0.0f, stageSize.width * 0.0125f );
302 mPaddleImage.SetParentOrigin( ParentOrigin::TOP_CENTER );
303 mPaddleImage.SetAnchorPoint( AnchorPoint::TOP_CENTER );
304 mPaddle.SetParentOrigin( ParentOrigin::TOP_LEFT );
305 mPaddle.SetAnchorPoint( AnchorPoint::CENTER );
306 mPaddleFullSize = PADDLE_SIZE * stageSize.width;
307 mPaddle.SetSize( mPaddleFullSize + mPaddleHitMargin );
308 mPaddleHandle.SetSize( PADDLE_HANDLE_SIZE * stageSize.width );
309 mPaddleImage.SetSize( mPaddleFullSize );
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();
316 mPaddle.SetPosition( stageSize * Vector3( PADDLE_START_POSITION ) );
317 mContentLayer.Add(mPaddle);
318 mPaddle.TouchSignal().Connect(this, &ExampleController::OnTouchPaddle);
319 mContentLayer.TouchSignal().Connect(this, &ExampleController::OnTouchLayer);
321 const float margin(BALL_SIZE.width * stageSize.width * 0.5f);
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 );
327 PropertyNotification rightNotification = mBall.AddPropertyNotification( Actor::Property::POSITION_X, GreaterThanCondition(stageSize.width - margin) );
328 rightNotification.NotifySignal().Connect( this, &ExampleController::OnHitRightWall );
330 PropertyNotification topNotification = mBall.AddPropertyNotification( Actor::Property::POSITION_Y, LessThanCondition(margin) );
331 topNotification.NotifySignal().Connect( this, &ExampleController::OnHitTopWall );
333 PropertyNotification bottomNotification = mBall.AddPropertyNotification( Actor::Property::POSITION_Y, GreaterThanCondition(stageSize.height + margin) );
334 bottomNotification.NotifySignal().Connect( this, &ExampleController::OnHitBottomWall );
336 // Set up notification for ball colliding against paddle.
337 Actor delegate = Actor::New();
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) );
347 PropertyNotification paddleNotification = delegate.AddPropertyNotification( property, GreaterThanCondition(0.0f) );
348 paddleNotification.NotifySignal().Connect( this, &ExampleController::OnHitPaddle );
355 * Resets Lives count and other stats, and loads level
359 mLives = TOTAL_LIVES;
361 mBall.SetPosition( mBallStartPosition );
362 mBallVelocity = Vector3::ZERO;
363 mPaddle.SetSize( mPaddleFullSize + mPaddleHitMargin );
364 mPaddleImage.SetSize( mPaddleFullSize );
371 * All existing level content is removed, and new bricks
373 * @param[in] level Level index to load.
375 void LoadLevel(int level)
377 if(mLevelContainer && mLevelContainer.GetParent() == mContentLayer)
379 mContentLayer.Remove( mLevelContainer );
382 mLevelContainer = Actor::New();
383 mLevelContainer.SetAnchorPoint( AnchorPoint::CENTER );
384 mLevelContainer.SetParentOrigin( ParentOrigin::CENTER );
385 mLevelContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
387 mContentLayer.Add( mLevelContainer );
391 if( mBrickImageMap.Empty() )
393 Vector2 stageSize(Stage::GetCurrent().GetSize());
394 const Vector2 brickSize(BRICK_SIZE * Vector2(stageSize.x, stageSize.x));
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";
402 switch(level%TOTAL_LEVELS)
429 void GenerateLevel0()
431 Vector2 stageSize(Stage::GetCurrent().GetSize());
432 const Vector2 brickSize(BRICK_SIZE * stageSize.width);
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 );
439 for(int j = 0; j < rows; j++)
441 for(int i = 0; i < columns; i++)
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);
453 void GenerateLevel1()
455 Vector2 stageSize(Stage::GetCurrent().GetSize());
456 const Vector2 brickSize(BRICK_SIZE * stageSize.width);
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 );
463 for(int j = 0; j < rows; j++)
465 for(int i = 0; i < columns; i++)
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;
471 Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), brickIndex );
473 mLevelContainer.Add(brick);
482 void GenerateLevel2()
484 Vector2 stageSize(Stage::GetCurrent().GetSize());
485 const Vector2 brickSize(BRICK_SIZE * stageSize.width);
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 );
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
499 // contracting boundaries
501 int right = columns - 1;
503 int bottom = rows - 1;
505 // length of current line. we stop laying down bricks when the length is 1 brick or less.
509 Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), 0 );
510 mLevelContainer.Add(brick);
514 if((i==right) && (di==1))
519 if((j==bottom) && (dj==1))
524 if((i==left) && (di==-1))
529 if((j==top) && (dj==-1))
536 // turn 90 degrees clockwise.
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.
557 Actor CreateBrick( const Vector2& position, int type )
559 mBrickImageMap["url"] = BRICK_IMAGE_PATH[type];
560 ImageView brick = ImageView::New();
561 brick.SetProperty( ImageView::Property::IMAGE, mBrickImageMap );
562 brick.SetParentOrigin(ParentOrigin::TOP_LEFT);
563 brick.SetAnchorPoint(AnchorPoint::CENTER);
564 brick.SetPosition( Vector3( position ) );
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) );
575 // Now add a notification on this collision-property
577 PropertyNotification brickNotification = brick.AddPropertyNotification( property, GreaterThanCondition(0.0f) );
578 brickNotification.NotifySignal().Connect( this, &ExampleController::OnHitBrick );
584 * Creates an Image (Helper)
586 * @param[in] filename the path of the image.
588 ImageView CreateImage(const std::string& filename)
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.SetParentOrigin(ParentOrigin::TOP_LEFT);
597 actor.SetAnchorPoint(AnchorPoint::CENTER);
602 * Continue animation (based on current velocity)
604 void ContinueAnimation()
608 mBallAnimation.Clear();
611 mBallAnimation = Animation::New(MAX_ANIMATION_DURATION);
612 mBallAnimation.AnimateBy( Property( mBall, Actor::Property::POSITION ), mBallVelocity * MAX_ANIMATION_DURATION);
613 mBallAnimation.Play();
617 * Signal invoked whenever user touches the Paddle.
618 * @param[in] actor The actor touched
619 * @param[in] event The touch event
621 bool OnTouchPaddle(Actor actor, const TouchData& event)
623 if(event.GetPointCount()>0)
625 if( event.GetState( 0 ) == PointState::DOWN ) // Commence dragging
627 // Get point where user touched paddle (relative to paddle's center)
628 Vector2 screenPoint = event.GetScreenPosition( 0 );
629 mRelativeDragPoint = screenPoint;
630 mRelativeDragPoint -= actor.GetCurrentPosition();
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();
643 * Signal invoked whenever user touches anywhere on the screen.
644 * @param[in] actor The actor touched
645 * @param[in] event The touch event
647 bool OnTouchLayer(Actor actor, const TouchData& event)
649 if(event.GetPointCount()>0)
653 Vector3 position( event.GetScreenPosition( 0 ) );
654 mPaddle.SetPosition( position - mRelativeDragPoint );
656 if( event.GetState( 0 ) == PointState::UP ) // Stop dragging
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();
670 * Notification: Ball hit left wall
671 * @param source The notification
673 void OnHitLeftWall(PropertyNotification& source)
675 mBallVelocity.x = fabsf(mBallVelocity.x);
680 * Notification: Ball hit right wall
681 * @param source The notification
683 void OnHitRightWall(PropertyNotification& source)
685 mBallVelocity.x = -fabsf(mBallVelocity.x);
690 * Notification: Ball hit top wall
691 * @param source The notification
693 void OnHitTopWall(PropertyNotification& source)
695 mBallVelocity.y = fabsf(mBallVelocity.y);
700 * Notification: Ball hit bottom wall
701 * @param source The notification
703 void OnHitBottomWall(PropertyNotification& source)
707 mBallAnimation.Clear();
713 const float f(static_cast<float>(mLives) / TOTAL_LIVES);
714 mBallVelocity = Vector3::ZERO;
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 );
720 shrink.FinishedSignal().Connect( this, &ExampleController::OnPaddleShrunk );
726 * Paddle Shrink Animation complete.
727 * @param[in] source The animation responsible for shrinking the paddle.
729 void OnPaddleShrunk( Animation &source )
731 // Reposition Ball in start position, and make ball appear.
732 mBall.SetPosition( mBallStartPosition );
733 mBall.SetColor( 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) );
745 * Notification: Ball hit paddle
746 * @param source The notification
748 void OnHitPaddle(PropertyNotification& source)
750 Actor delegate = Actor::DownCast(source.GetTarget());
751 Vector3 collisionVector = delegate.GetCurrentProperty< Vector3 >( source.GetTargetProperty() );
752 Vector3 ballRelativePosition(mBall.GetCurrentPosition() - mPaddle.GetCurrentPosition());
753 ballRelativePosition.Normalize();
755 collisionVector.x += ballRelativePosition.x * 0.5f;
757 if(mBallVelocity.LengthSquared() < Math::MACHINE_EPSILON_1)
759 mBallVelocity += collisionVector * BALL_VELOCITY;
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;
773 mWobbleAnimation = Animation::New(0.5f);
774 mWobbleAnimation.AnimateTo( Property( mPaddle, mWobbleProperty ), 1.0f );
775 mWobbleAnimation.Play();
776 mPaddle.SetProperty(mWobbleProperty, 0.0f);
780 * Notification: Ball hit brick
781 * @param source The notification
783 void OnHitBrick(PropertyNotification& source)
785 Actor brick = Actor::DownCast(source.GetTarget());
786 Vector3 collisionVector = brick.GetCurrentProperty< Vector3 >( source.GetTargetProperty() );
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;
796 // remove collision-constraint and notification.
797 brick.RemovePropertyNotification(source);
798 brick.RemoveConstraints();
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;
809 * Brick Destruction Animation complete.
810 * @param[in] source The animation responsible for destroying the brick
812 void OnBrickDestroyed( Animation& source )
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);
828 * Main key event handler
830 void OnKeyEvent(const KeyEvent& event)
832 if(event.state == KeyEvent::Down)
834 if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
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
859 // actor - dragging functionality
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.
871 int DALI_EXPORT_API main(int argc, char **argv)
873 Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
874 ExampleController test(app);