2 * Copyright (c) 2020 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-toolkit/dali-toolkit.h>
25 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
26 #include <dali/dali.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 window.
64 const Vector2 BALL_SIZE(0.05f, 0.05f); ///< Ball size relative to width of window.
65 const Vector2 PADDLE_SIZE(0.2f, 0.05f); ///< Paddle size relative to width of window.
66 const Vector2 PADDLE_HANDLE_SIZE(0.3f, 0.3f); ///< Paddle handle size relative to width of window.
67 const Vector2 BALL_START_POSITION(0.5f, 0.8f); ///< Ball start position relative to window size.
68 const Vector2 PADDLE_START_POSITION(0.5f, 0.9f); ///< Paddler start position relative to window 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)
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.
190 void operator()(Quaternion& current, const PropertyInputContainer& inputs)
192 const float& wobble = inputs[0]->GetFloat();
194 float f = sinf(wobble * 10.0f) * (1.0f - wobble);
196 current = Quaternion(mDeviation * f, Vector3::ZAXIS);
199 Radian mDeviation; ///< Deviation factor in radians.
202 } // unnamed namespace
205 * This example shows how to use PropertyNotifications
207 class ExampleController : public ConnectionTracker
212 * @param application Application class, stored as reference
214 ExampleController(Application& application)
215 : mApplication(application),
219 mBallStartPosition(),
227 mWobbleProperty(Property::INVALID_INDEX),
232 mRelativeDragPoint(),
233 mDestroyAnimationMap(),
240 // Connect to the Application's Init and orientation changed signal
241 mApplication.InitSignal().Connect(this, &ExampleController::Create);
245 * This method gets called once the main loop of application is up and running
246 * @param[in] application Reference to the application instance
248 void Create(Application& application)
250 application.GetWindow().KeyEventSignal().Connect(this, &ExampleController::OnKeyEvent);
252 // Creates a default view with a default tool bar.
253 // The view is added to the window.
254 Toolkit::ToolBar toolBar;
255 mContentLayer = DemoHelper::CreateView(application,
262 // Add an extra space on the right to center the title text.
263 toolBar.AddControl(Actor::New(), DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HORIZONTAL_RIGHT);
265 // Create the content layer, which is where game actors appear.
271 * Adds a new layer to the window, containing game actors.
273 void AddContentLayer()
275 Window window = mApplication.GetWindow();
276 const Vector3 windowSize(window.GetSize());
279 mBallStartPosition = windowSize * Vector3(BALL_START_POSITION);
280 mBall = CreateImage(BALL_IMAGE);
281 mBall.SetProperty(Actor::Property::POSITION, mBallStartPosition);
282 mBall.SetProperty(Actor::Property::SIZE, BALL_SIZE * windowSize.width);
283 mContentLayer.Add(mBall);
284 mBallVelocity = Vector3::ZERO;
287 mPaddleHitMargin = Vector2(windowSize) * PADDLE_HIT_MARGIN;
288 mPaddle = Actor::New();
289 mPaddleHandle = CreateImage(PADDLE_HANDLE_IMAGE);
290 mPaddleImage = CreateImage(PADDLE_IMAGE);
291 mPaddle.Add(mPaddleHandle);
292 mPaddle.Add(mPaddleImage);
293 mPaddleHandle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
294 mPaddleHandle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
295 mPaddleHandle.SetProperty(Actor::Property::POSITION, Vector2(0.0f, windowSize.width * 0.0125f));
296 mPaddleImage.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
297 mPaddleImage.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
298 mPaddle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
299 mPaddle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
300 mPaddleFullSize = PADDLE_SIZE * windowSize.width;
301 mPaddle.SetProperty(Actor::Property::SIZE, mPaddleFullSize + mPaddleHitMargin);
302 mPaddleHandle.SetProperty(Actor::Property::SIZE, PADDLE_HANDLE_SIZE * windowSize.width);
303 mPaddleImage.SetProperty(Actor::Property::SIZE, mPaddleFullSize);
305 mWobbleProperty = mPaddle.RegisterProperty(WOBBLE_PROPERTY_NAME, 0.0f);
306 Constraint wobbleConstraint = Constraint::New<Quaternion>(mPaddle, Actor::Property::ORIENTATION, WobbleConstraint(Degree(10.0f)));
307 wobbleConstraint.AddSource(LocalSource(mWobbleProperty));
308 wobbleConstraint.Apply();
310 mPaddle.SetProperty(Actor::Property::POSITION, windowSize * Vector3(PADDLE_START_POSITION));
311 mContentLayer.Add(mPaddle);
312 mPaddle.TouchedSignal().Connect(this, &ExampleController::OnTouchPaddle);
313 mContentLayer.TouchedSignal().Connect(this, &ExampleController::OnTouchLayer);
315 const float margin(BALL_SIZE.width * windowSize.width * 0.5f);
317 // Set up notifications for ball's collisions against walls.
318 PropertyNotification leftNotification = mBall.AddPropertyNotification(Actor::Property::POSITION_X, LessThanCondition(margin));
319 leftNotification.NotifySignal().Connect(this, &ExampleController::OnHitLeftWall);
321 PropertyNotification rightNotification = mBall.AddPropertyNotification(Actor::Property::POSITION_X, GreaterThanCondition(windowSize.width - margin));
322 rightNotification.NotifySignal().Connect(this, &ExampleController::OnHitRightWall);
324 PropertyNotification topNotification = mBall.AddPropertyNotification(Actor::Property::POSITION_Y, LessThanCondition(margin));
325 topNotification.NotifySignal().Connect(this, &ExampleController::OnHitTopWall);
327 PropertyNotification bottomNotification = mBall.AddPropertyNotification(Actor::Property::POSITION_Y, GreaterThanCondition(windowSize.height + margin));
328 bottomNotification.NotifySignal().Connect(this, &ExampleController::OnHitBottomWall);
330 // Set up notification for ball colliding against paddle.
331 Actor delegate = Actor::New();
332 window.Add(delegate);
333 Property::Index property = delegate.RegisterProperty(COLLISION_PROPERTY_NAME, Vector3::ZERO);
334 Constraint constraint = Constraint::New<Vector3>(delegate, property, CollisionCircleRectangleConstraint(-Vector3(0.0f, mPaddleHitMargin.height * 0.575f, 0.0f), -Vector3(mPaddleHitMargin)));
335 constraint.AddSource(Source(mBall, Actor::Property::POSITION));
336 constraint.AddSource(Source(mPaddle, Actor::Property::POSITION));
337 constraint.AddSource(Source(mBall, Actor::Property::SIZE));
338 constraint.AddSource(Source(mPaddle, Actor::Property::SIZE));
341 PropertyNotification paddleNotification = delegate.AddPropertyNotification(property, GreaterThanCondition(0.0f));
342 paddleNotification.NotifySignal().Connect(this, &ExampleController::OnHitPaddle);
349 * Resets Lives count and other stats, and loads level
353 mLives = TOTAL_LIVES;
355 mBall.SetProperty(Actor::Property::POSITION, mBallStartPosition);
356 mBallVelocity = Vector3::ZERO;
357 mPaddle.SetProperty(Actor::Property::SIZE, mPaddleFullSize + mPaddleHitMargin);
358 mPaddleImage.SetProperty(Actor::Property::SIZE, mPaddleFullSize);
365 * All existing level content is removed, and new bricks
367 * @param[in] level Level index to load.
369 void LoadLevel(int level)
371 if(mLevelContainer && mLevelContainer.GetParent() == mContentLayer)
373 mContentLayer.Remove(mLevelContainer);
376 mLevelContainer = Actor::New();
377 mLevelContainer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
378 mLevelContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
379 mLevelContainer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
381 mContentLayer.Add(mLevelContainer);
385 if(mBrickImageMap.Empty())
387 Vector2 windowSize(mApplication.GetWindow().GetSize());
388 const Vector2 brickSize(BRICK_SIZE * Vector2(windowSize.x, windowSize.x));
390 mBrickImageMap["desiredWidth"] = static_cast<int>(brickSize.width);
391 mBrickImageMap["desiredHeight"] = static_cast<int>(brickSize.height);
392 mBrickImageMap["fittingMode"] = "SCALE_TO_FILL";
393 mBrickImageMap["samplingMode"] = "BOX_THEN_LINEAR";
396 switch(level % TOTAL_LEVELS)
423 void GenerateLevel0()
425 Vector2 windowSize(mApplication.GetWindow().GetSize());
426 const Vector2 brickSize(BRICK_SIZE * windowSize.width);
428 const int columns = (0.85f * windowSize.width) / brickSize.width; // 85 percent of the width of the screen covered with bricks.
429 const int rows = (0.3f * windowSize.height) / brickSize.height; // 30 percent of the height of the screen covered with bricks.
430 const Vector2 offset((windowSize.x - (columns * brickSize.width)) * 0.5f,
431 windowSize.y * 0.125f);
433 for(int j = 0; j < rows; j++)
435 for(int i = 0; i < columns; i++)
437 Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), j % TOTAL_BRICKS);
438 mLevelContainer.Add(brick);
447 void GenerateLevel1()
449 Vector2 windowSize(mApplication.GetWindow().GetSize());
450 const Vector2 brickSize(BRICK_SIZE * windowSize.width);
452 const int columns = (0.85f * windowSize.width) / brickSize.width; // 85 percent of the width of the screen covered with bricks.
453 const int rows = (0.3f * windowSize.height) / brickSize.height; // 30 percent of the height of the screen covered with bricks.
454 const Vector2 offset((windowSize.x - (columns * brickSize.width)) * 0.5f,
455 windowSize.y * 0.125f);
457 for(int j = 0; j < rows; j++)
459 for(int i = 0; i < columns; i++)
461 int i2 = columns - i - 1;
462 int j2 = rows - j - 1;
463 int brickIndex = std::min(std::min(i, j), std::min(i2, j2)) % TOTAL_BRICKS;
465 Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), brickIndex);
467 mLevelContainer.Add(brick);
476 void GenerateLevel2()
478 Vector2 windowSize(mApplication.GetWindow().GetSize());
479 const Vector2 brickSize(BRICK_SIZE * windowSize.width);
481 const int columns = (0.85f * windowSize.width) / brickSize.width; // 85 percent of the width of the screen covered with bricks.
482 const int rows = (0.3f * windowSize.height) / brickSize.height; // 30 percent of the height of the screen covered with bricks.
483 const Vector2 offset((windowSize.x - (columns * brickSize.width)) * 0.5f,
484 windowSize.y * 0.125f);
486 // lays down bricks in a spiral formation starting at i,j = (0,0) top left corner
487 // travelling right di,dj = (1,0) initially
493 // contracting boundaries
495 int right = columns - 1;
497 int bottom = rows - 1;
499 // length of current line. we stop laying down bricks when the length is 1 brick or less.
503 Actor brick = CreateBrick(Vector2(i * brickSize.width + offset.x, j * brickSize.height + offset.y) + (brickSize * 0.5f), 0);
504 mLevelContainer.Add(brick);
508 if((i == right) && (di == 1))
513 if((j == bottom) && (dj == 1))
518 if((i == left) && (di == -1))
523 if((j == top) && (dj == -1))
530 // turn 90 degrees clockwise.
545 * Creates a brick at a specified position on the window
546 * @param[in] position the position for the brick
547 * @param[in] type the type of brick
548 * @return The Brick Actor is returned.
550 Actor CreateBrick(const Vector2& position, int type)
552 mBrickImageMap["url"] = BRICK_IMAGE_PATH[type];
553 ImageView brick = ImageView::New();
554 brick.SetProperty(ImageView::Property::IMAGE, mBrickImageMap);
555 brick.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
556 brick.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
557 brick.SetProperty(Actor::Property::POSITION, position);
559 // Add a constraint on the brick between it and the ball generating a collision-property
560 Property::Index property = brick.RegisterProperty(COLLISION_PROPERTY_NAME, Vector3::ZERO);
561 Constraint constraint = Constraint::New<Vector3>(brick, property, CollisionCircleRectangleConstraint(BRICK_COLLISION_MARGIN));
562 constraint.AddSource(Source(mBall, Actor::Property::POSITION));
563 constraint.AddSource(Source(brick, Actor::Property::POSITION));
564 constraint.AddSource(Source(mBall, Actor::Property::SIZE));
565 constraint.AddSource(Source(brick, Actor::Property::SIZE));
568 // Now add a notification on this collision-property
570 PropertyNotification brickNotification = brick.AddPropertyNotification(property, GreaterThanCondition(0.0f));
571 brickNotification.NotifySignal().Connect(this, &ExampleController::OnHitBrick);
577 * Creates an Image (Helper)
579 * @param[in] filename the path of the image.
581 ImageView CreateImage(const std::string& filename)
583 Property::Map propertyMap;
584 propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
585 propertyMap.Insert(ImageVisual::Property::URL, filename);
586 propertyMap.Insert(DevelVisual::Property::VISUAL_FITTING_MODE, DevelVisual::FILL);
587 ImageView actor = ImageView::New();
588 actor.SetProperty(Toolkit::ImageView::Property::IMAGE, propertyMap);
589 actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
590 actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
595 * Continue animation (based on current velocity)
597 void ContinueAnimation()
601 mBallAnimation.Clear();
604 mBallAnimation = Animation::New(MAX_ANIMATION_DURATION);
605 mBallAnimation.AnimateBy(Property(mBall, Actor::Property::POSITION), mBallVelocity * MAX_ANIMATION_DURATION);
606 mBallAnimation.Play();
610 * Signal invoked whenever user touches the Paddle.
611 * @param[in] actor The actor touched
612 * @param[in] event The touch event
614 bool OnTouchPaddle(Actor actor, const TouchEvent& event)
616 if(event.GetPointCount() > 0)
618 if(event.GetState(0) == PointState::DOWN) // Commence dragging
620 // Get point where user touched paddle (relative to paddle's center)
621 Vector2 screenPoint = event.GetScreenPosition(0);
622 mRelativeDragPoint = screenPoint;
623 mRelativeDragPoint -= actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
626 mDragAnimation = Animation::New(0.25f);
627 mDragAnimation.AnimateTo(Property(mDragActor, Actor::Property::SCALE), Vector3(1.1f, 1.1f, 1.0f), AlphaFunction::EASE_OUT);
628 mDragAnimation.AnimateTo(Property(mPaddleHandle, Actor::Property::COLOR), Vector4(1.0f, 1.0f, 1.0f, 0.0f), AlphaFunction::EASE_OUT);
629 mDragAnimation.Play();
636 * Signal invoked whenever user touches anywhere on the screen.
637 * @param[in] actor The actor touched
638 * @param[in] event The touch event
640 bool OnTouchLayer(Actor actor, const TouchEvent& event)
642 if(event.GetPointCount() > 0)
646 Vector3 position(event.GetScreenPosition(0));
647 mPaddle.SetProperty(Actor::Property::POSITION, position - mRelativeDragPoint);
649 if(event.GetState(0) == PointState::UP) // Stop dragging
651 mDragAnimation = Animation::New(0.25f);
652 mDragAnimation.AnimateTo(Property(mDragActor, Actor::Property::SCALE), Vector3(1.0f, 1.0f, 1.0f), AlphaFunction::EASE_IN);
653 mDragAnimation.AnimateTo(Property(mPaddleHandle, Actor::Property::COLOR), Vector4(1.0f, 1.0f, 1.0f, 1.0f), AlphaFunction::EASE_OUT);
654 mDragAnimation.Play();
663 * Notification: Ball hit left wall
664 * @param source The notification
666 void OnHitLeftWall(PropertyNotification& source)
668 mBallVelocity.x = fabsf(mBallVelocity.x);
673 * Notification: Ball hit right wall
674 * @param source The notification
676 void OnHitRightWall(PropertyNotification& source)
678 mBallVelocity.x = -fabsf(mBallVelocity.x);
683 * Notification: Ball hit top wall
684 * @param source The notification
686 void OnHitTopWall(PropertyNotification& source)
688 mBallVelocity.y = fabsf(mBallVelocity.y);
693 * Notification: Ball hit bottom wall
694 * @param source The notification
696 void OnHitBottomWall(PropertyNotification& source)
700 mBallAnimation.Clear();
706 const float f(static_cast<float>(mLives) / TOTAL_LIVES);
707 mBallVelocity = Vector3::ZERO;
709 Animation shrink = Animation::New(0.5f);
710 shrink.AnimateTo(Property(mPaddle, Actor::Property::SIZE_WIDTH), mPaddleFullSize.x * f + mPaddleHitMargin.x);
711 shrink.AnimateTo(Property(mPaddleImage, Actor::Property::SIZE_WIDTH), mPaddleFullSize.x * f);
713 shrink.FinishedSignal().Connect(this, &ExampleController::OnPaddleShrunk);
719 * Paddle Shrink Animation complete.
720 * @param[in] source The animation responsible for shrinking the paddle.
722 void OnPaddleShrunk(Animation& source)
724 // Reposition Ball in start position, and make ball appear.
725 mBall.SetProperty(Actor::Property::POSITION, mBallStartPosition);
726 mBall.SetProperty(Actor::Property::COLOR, Vector4(1.0f, 1.0f, 1.0f, 0.1f));
727 Animation appear = Animation::New(0.5f);
728 appear.AnimateTo(Property(mBall, Actor::Property::COLOR), Vector4(1.0f, 1.0f, 1.0f, 1.0f));
738 * Notification: Ball hit paddle
739 * @param source The notification
741 void OnHitPaddle(PropertyNotification& source)
743 Actor delegate = Actor::DownCast(source.GetTarget());
744 Vector3 collisionVector = delegate.GetCurrentProperty<Vector3>(source.GetTargetProperty());
745 Vector3 ballRelativePosition(mBall.GetCurrentProperty<Vector3>(Actor::Property::POSITION) - mPaddle.GetCurrentProperty<Vector3>(Actor::Property::POSITION));
746 ballRelativePosition.Normalize();
748 collisionVector.x += ballRelativePosition.x * 0.5f;
750 if(mBallVelocity.LengthSquared() < Math::MACHINE_EPSILON_1)
752 mBallVelocity += collisionVector * BALL_VELOCITY;
756 const float normalVelocity = fabsf(mBallVelocity.Dot(collisionVector));
757 mBallVelocity += collisionVector * normalVelocity * 2.0f;
758 const float currentSpeed = mBallVelocity.Length();
759 const float limitedSpeed = std::min(currentSpeed, MAX_VELOCITY);
760 mBallVelocity = mBallVelocity * limitedSpeed / currentSpeed;
766 mWobbleAnimation = Animation::New(0.5f);
767 mWobbleAnimation.AnimateTo(Property(mPaddle, mWobbleProperty), 1.0f);
768 mWobbleAnimation.Play();
769 mPaddle.SetProperty(mWobbleProperty, 0.0f);
773 * Notification: Ball hit brick
774 * @param source The notification
776 void OnHitBrick(PropertyNotification& source)
778 Actor brick = Actor::DownCast(source.GetTarget());
779 Vector3 collisionVector = brick.GetCurrentProperty<Vector3>(source.GetTargetProperty());
781 const float normalVelocity = fabsf(mBallVelocity.Dot(collisionVector));
782 mBallVelocity += collisionVector * normalVelocity * 2.0f;
783 const float currentSpeed = mBallVelocity.Length();
784 const float limitedSpeed = std::min(currentSpeed, MAX_VELOCITY);
785 mBallVelocity = mBallVelocity * limitedSpeed / currentSpeed;
789 // remove collision-constraint and notification.
790 brick.RemovePropertyNotification(source);
791 brick.RemoveConstraints();
793 // fade brick (destroy)
794 Animation destroyAnimation = Animation::New(0.5f);
795 destroyAnimation.AnimateTo(Property(brick, Actor::Property::COLOR_ALPHA), 0.0f, AlphaFunction::EASE_IN);
796 destroyAnimation.Play();
797 destroyAnimation.FinishedSignal().Connect(this, &ExampleController::OnBrickDestroyed);
798 mDestroyAnimationMap[destroyAnimation] = brick;
802 * Brick Destruction Animation complete.
803 * @param[in] source The animation responsible for destroying the brick
805 void OnBrickDestroyed(Animation& source)
807 // Remove brick from window, it's constraint and property notification should also remove themselves.
808 Actor brick = mDestroyAnimationMap[source];
809 mDestroyAnimationMap.erase(source);
810 brick.GetParent().Remove(brick);
821 * Main key event handler
823 void OnKeyEvent(const KeyEvent& event)
825 if(event.GetState() == KeyEvent::DOWN)
827 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
835 Application& mApplication; ///< Application instance
836 Toolkit::Control mView; ///< The View instance.
837 Layer mContentLayer; ///< The content layer (contains game actors)
838 ImageView mBall; ///< The Moving ball image.
839 Vector3 mBallStartPosition; ///< Ball Start position
840 Vector3 mBallVelocity; ///< Ball's current direction.
841 Animation mBallAnimation; ///< Ball's animation
842 Actor mPaddle; ///< The paddle including hit area.
843 ImageView mPaddleImage; ///< The paddle's image.
844 ImageView mPaddleHandle; ///< The paddle's handle (where the user touches)
845 Vector2 mPaddleHitMargin; ///< The paddle hit margin.
846 Animation mWobbleAnimation; ///< Paddle's animation when hit (wobbles)
847 Property::Index mWobbleProperty; ///< The wobble property (generated from animation)
848 Actor mLevelContainer; ///< The level container (contains bricks)
849 Property::Map mBrickImageMap; ///< The property map used to load the brick
851 // actor - dragging functionality
853 Animation mDragAnimation; ///< Animation for dragging. (grows - affects ACTOR::SCALE)
854 Actor mDragActor; ///< The actor which is being dragged (if any)
855 Vector3 mRelativeDragPoint; ///< The point the user touched, relative to the actor.
856 std::map<Animation, Actor> mDestroyAnimationMap; ///< Keep track of which actors are to be destroyed.
857 Vector2 mPaddleFullSize; ///< Initial 100% size of the paddle.
858 int mLevel; ///< Current level
859 int mLives; ///< Total lives.
860 int mBrickCount; ///< Total bricks on screen.
863 int DALI_EXPORT_API main(int argc, char** argv)
865 Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
866 ExampleController test(app);