Cascades animations in games

by Roger Leblanc

This article is a follow-up of How to use Cascades built-in animations

Animations are perfect for simple games, so let’s create one right now. The game we’ll be building is called ‘No Fly Zone’ and consist of a fly flying around the screen that we need to kill. First, we’ll need a fly image, so I’ve found this one from http://www.openclipart.org :

Fly

 

We’ll separate this image in two parts : the body and wings. Save those 2 images in ‘assets/images/’ folder (you’ll need to create ‘images’ folder).

fly_wingsfly_body

To make the wings flap, we’ll put both images on top of each other and then set a small back and forth rotation transition to the wings. Let’s create a custom component for that fly and name it FlyImage.qml :

 

// FlyImage.qml
import bb.cascades 1.0

Container {
    id: flyContainer
    layout: DockLayout {}
    property int angleForWingsFlapping: 20

    maxHeight: 100
    maxWidth: maxHeight
    
    ImageView {
        imageSource: "asset:///images/fly_wings.png"
        onCreationCompleted: {
            wingsFlappingAnimation.play()
        }
        animations: [
            SequentialAnimation {
                id: wingsFlappingAnimation
                repeatCount: AnimationRepeatCount.Forever
                RotateTransition {
                    // Rotate wings clockwise slightly
                    toAngleZ: angleForWingsFlapping
                    duration: 2
                }
                RotateTransition {
                    // Rotate wings counterclockwise slightly
                    toAngleZ: 0 - angleForWingsFlapping
                    duration: 2
                }
            }
        ]
    }
    
    ImageView {
        id: flyBodyImage
        imageSource: "asset:///images/fly_body.png"
    }
}

Now, in main.qml, we can add this custom component by calling its name, and we’ll have a fly with flapping wings on the screen :

// main.qml
import bb.cascades 1.0

Page {
    content: Container {
        FlyImage {}
    }
}

Now that we have a fly with animated wings, let’s move that fly around the screen :

 

// main.qml
import bb.cascades 1.0

Page {
    id: mainPage
    
    // You may need to change deviceWidth and deviceHeight values depending on your device
    property int deviceWidth: 1440
    property int deviceHeight: 1440
    property int speed: 3000
    
    onCreationCompleted: {
        // Starts the animation when the app launch
        thisAnimation.play()
    }
    
    content: Container {
        layout: DockLayout {}
        background: Color.LightGray
        horizontalAlignment: HorizontalAlignment.Fill
        verticalAlignment: VerticalAlignment.Fill
        
        FlyImage {
            id: flyImageAlive
            
            maxHeight: 100
            maxWidth: maxHeight
            
            // Starts at the bottom of the screen                        
            translationX: Math.random() * deviceWidth 
            translationY: deviceHeight + 100
            
            animations: [
                ParallelAnimation {
                    id: thisAnimation
                    
                    onEnded: {
                        // This is what happens when one animation cycle is done
                        
                        // Recalculate new translation points
                        thisTranslation.toX = Math.random() * deviceWidth
                        thisTranslation.toY = Math.random() * deviceHeight
                        
                        // Recalculate new scale transition value
                        thisScale.toX = (Math.random() * 1.5) + 0.5
                        thisScale.toY = thisScale.toX
                        
                        // Restart the animation with the new values
                        thisAnimation.play()
                    }
                    
                    TranslateTransition {
                        // Move the fly toX and toY values
                        id: thisTranslation
                        duration: speed
                        easingCurve: StockCurve.Linear
                        toX: Math.random() * deviceWidth
                        toY: Math.random() * deviceHeight
                    }
                    
                    ScaleTransition {
                        // Rescale the fly randomly
                        id: thisScale
                        duration: speed
                        toX: (Math.random() * 1.5) + 0.5
                        toY: toX
                    }
                }
            ]
        }
    }
}

So now we have a fly flying randomly around the screen. Only thing left to do is handling tap event for when the user hit the fly and creating a score board, and there you have a simple game using Cascades built-in animations.

Complete source code is available on GitHub

You can find ‘No Fly Zone’ free game in BlackBerry World at :
http://appworld.blackberry.com/webstore/content/59946084

How to use Cascades built-in animations

by Roger Leblanc

Nowadays, there’s a lot of mobile app developers and your apps need to stand out to catch the user’s attention. Most users like to interact with the app, and animations can bring this interaction to another level, not only letting the user touch a component on the screen and have a reaction, but also having this component to move, scale, fade or rotate to create a real sense of interaction and fluidity.

Hopefully, Cascades makes it easy to use animations with only a few lines of code.

 

IMPLICIT AND EXPLICIT ANIMATIONS

Cascades support 2 types of animations, implicit and explicit animations. Implicit animations doesn’t need any coding and can be used on 2 types of properties :

  • Properties that determine how a control looks, such as rotation, translation, and opacity
  • Properties that determine the layout of a control in a container, such as preferred width and preferred height

So if you set the opacity of a Button to 0, it will fade out gradually instead of becoming invisible right away. Cascades takes care of the animation, you don’t have to write any line of code for this fade out animation.

Here’s some sample code to test implicit animations :

import bb.cascades 1.0

Page {
    
    content: Button {
        
        text: "Click me"
        
        onClicked: {
            
            translationX += 20
            
            opacity -= 0.2
            
            if (opacity == 0)
                
                opacity = 1
        
        }
    
    }

}

EXPLICIT ANIMATIONS : FADE, ROTATE, TRANSLATE, SCALE

If you want to have more control on the animation used, then you’ll want to look into explicit animations, where you can set from and to values, duration, easing curve, a delay before the animation start or number of repeat for your animation. Let’s take a fade transition, we want a Button to fade slowly from 1.0 to 0.0 and make it repeat forever :

import bb.cascades 1.0

Page {
    
    content: Container {
        
        Button {
            
            text: "Click me"
            
            animations: [
                
                FadeTransition {
                    
                    id: fadeTransition
                    
                    duration: 3000
                    
                    fromOpacity: 1.0
                    
                    toOpacity: 0.0
                    
                    repeatCount: AnimationRepeatCount.Forever
                
                }
            
            ]
            
            onClicked: {
                
                fadeTransition.play()
            
            }
        
        }
    
    }

}

So we have a better control of the animation with an explicit animation. There are 4 types of animations that can be controlled with explicit animation :

  • Fade transition
  • Rotate transition
  • Translate transition
  • Scale transition

 

GROUP ANIMATIONS

It’s even possible to group animations together and make them perform one after the other or all at the same time. Those are called SequentialAnimation and ParallelAnimation. Let’s try both to see the difference.

import bb.cascades 1.0

Page {
    content: Container {
        Button {
            text: "Click me"
            
            animations: [
                ParallelAnimation {
                    id: parallelAnimation
                    
                    animations: [
                        TranslateTransition {
                            toX: 400
                            duration: 2000
                        },
                        RotateTransition {
                            toAngleZ: 180
                            duration: 2000
                        }
                    ]
                }
            ]
            
            onClicked: {
                parallelAnimation.play();
            }
        }
        Button {
            text: "Click me"
            
            animations: [
                SequentialAnimation {
                    id: sequentialAnimation
                    
                    animations: [
                        TranslateTransition {
                            toX: 400
                            duration: 2000
                        },
                        RotateTransition {
                            toAngleZ: 180
                            duration: 2000
                        }
                    ]
                }
            ]
            
            onClicked: {
                sequentialAnimation.play();
            }
        }
    }
}

For now, all the animations used were a little bit useless, but they showed possibilities. For a real life example, let’s say we have a freemium app and we want to invite the user to upgrade to Pro version, we can do it like this :

import bb.cascades 1.0

Page {
    property int deviceWidth: 1440 // Set it to your screen width
    property int deviceHeight: 1440 // Set it to your screen height
    content: Container {
        layout: DockLayout {}
        horizontalAlignment: HorizontalAlignment.Fill
        verticalAlignment: VerticalAlignment.Fill
        Container {
            id: mainAppContainer
            Label {
                text: "This is your main app"
            }
            Container {
                topPadding: 30
                Button {
                    text: "Random action that prompt user to upgrade"
                    onClicked: upgradeContainer.visible = true
                }
            }
        }
        Container {
            id: upgradeContainer
            background: Color.Black
            horizontalAlignment: HorizontalAlignment.Fill
            verticalAlignment: VerticalAlignment.Fill
            opacity: 0.7
            visible: false
            onVisibleChanged: {
                if (visible) {
                    upgradeButton.translationX = deviceWidth // Make it out of sight
                    upgradeButton.translationY = deviceHeight // Make it out of sight
                    noThanksButton.translationX = deviceWidth // Make it out of sight
                    noThanksButton.translationY = deviceHeight // Make it out of sight
                    
                    upgradeButtonAnimation.play()
                    noThanksButtonAnimation.play()
                } 
            }
            Button {
                id: upgradeButton
                text: "Upgrade"
                preferredWidth: 300
                preferredHeight: 30
                onClicked: upgradeContainer.visible = false
                animations: [
                    ParallelAnimation {
                        id: upgradeButtonAnimation
                        RotateTransition {
                            fromAngleZ: 160
                            toAngleZ: 0
                            duration: 1500
                            easingCurve: StockCurve.ElasticOut
                        }
                        TranslateTransition {
                            fromX: deviceWidth * 0.75
                            fromY: deviceHeight
                            toX: (deviceWidth / 2) - (upgradeButton.preferredWidth / 2)
                            toY: (deviceHeight / 2) - (upgradeButton.preferredHeight / 2)
                            duration: 1500
                            easingCurve: StockCurve.ElasticOut 
                        }
                    }
                ]
            }
            Button {
                id: noThanksButton
                text: "No Thanks"
                preferredWidth: 300
                preferredHeight: 30
                onClicked: upgradeContainer.visible = false
                animations: [
                    ParallelAnimation {
                        id: noThanksButtonAnimation
                        delay: 4000 // Setting a delay will make this button appear later
                        RotateTransition {
                            fromAngleZ: 160
                            toAngleZ: 0
                            duration: 1500
                            easingCurve: StockCurve.ElasticOut
                        }
                        TranslateTransition {
                            fromX: deviceWidth * 0.75
                            fromY: deviceHeight
                            toX: (deviceWidth / 2) - (noThanksButton.preferredWidth / 2)
                            toY: (deviceHeight / 2) - (noThanksButton.preferredHeight / 2) + upgradeButton.preferredHeight
                            duration: 1500
                            easingCurve: StockCurve.ElasticOut
                        }
                    }
                ]
            }
        }
    }
}

What’s happening here is when a certain action is performed by the user, it shows a semi-transparent black screen (opacity 0.7) and then 2 buttons comes from out of sight to the middle of the screen, an ‘Upgrade’ button and a ‘No Thanks’ button. User have to click either one to continue to use the app.

Animations can be a lot of fun in Cascades, it’s powerful, simple to code and look nice. It allows your app to stand out from the crowd, so go ahead, and play with it!

Reference : https://developer.blackberry.com/native/documentation/cascades/ui/animations/index.html

JavaScript last day of the month

by DeanLogic Passport

I usually don’t do post about simple JavaScript issues, but I figured I might need this solution again and might as well write it down.

I am working on a new product called Archibus Web Central. Basically it is a building inventory management tool. The application is made up of an XML and JavaScript Hybrid code. Poor explanation, but not really important to this post.

In the project I am working on, I need to determine a start and end date in order to get a range of dates. To make my life simple, I am just using a set of drop lists with months and years as options. After the start and end values are collected, I want to set the date range to the 1st day of the month for the start selection and the last day of the month for the end selection.

i.e. August 2014 gives me 08/01/2014 if it is the start and 08/31/2014 if it is the end.

Well, since JavaScript doesn’t have a LastDay() function, I need to calculate what is the last day. And, since months are different and leap year and such, I can’t simply just put 30 as the Day in the Date object. The key is to get the next month and subtract from there.


//get the drop lists and the selected values

var eYear = document.getElementById('endYearList');

var eYearValue = eYear.options[eYear.selectedIndex].value;

var eMonth = document.getElementById('endMonthList');

var eMonthValue = eMonth.options[eMonth.selectedIndex].value;

//create the Date object

var endDate = new Date(eYearValue,eMonthValue ,1,0,0,0,0);

//create the Date object that will provide the Day value

var endDateDate = new Date(endDate).setMonth() + 1);

//set the Day with the endDateDate

endDate.setDate(new Date(endDateDate - 1).getDate)):

It might not be the smallest or best code, but at least I know that it provides the correct value.

Built for BlackBerry

by DeanLogic Passport

built_for_blackberry_10_logo_black_rgbJust because you build an app to run on a BlackBerry device, doesn’t mean that it is Built for BlackBerry. There are guidelines for what is considered Built for BlackBerry. And after you think you have done your best to meet those guidelines, you have to submit your app to be scrutinized by someone from BlackBerry to determine if you did meet those guidelines. On top of that, you only get a limited number of tries to get the app passed.

Built for BlackBerry. The signature BlackBerry 10 experience. Built to keep you moving, apps and games with the Built for BlackBerry designation provide the seamless performance and integrated experience you’ve come to love. Look for the Built for BlackBerry badge to identify apps and games that deliver the signature BlackBerry 10 experience

Well, after two tries, Meetup for BlackBerry 10 by DeanLogic is now officially a Built for BlackBerry app. The best part is that I don’t have to do anything to my app page, it gets a sticker automagically.

Meetup for BlackBerry Built for BlackBerry

But, there is still more work to be done on the app.

Meetup for BlackBerry 1.2.2

by DeanLogic Passport

Meetup for BlackBerry 10 iconMeetup for BlackBerry 10 by DeanLogic version 1.2.2 is now available for download.

The first thing you should notice is that the install size is now only 1.5 MB. Sorry for making it so huge before, I didn’t realize the splash screen images were the culprit.

The other obvious change is the app icon. Due to a request from Meetup, I modified the logo to meet their requirements.

I added shortcut keys for the Q and Passport, but found out that the ‘Alt’ key won’t work for those shortcuts. I will do a different shortcut and send out an update.

I added the ability to reply to Chat in an Event. This is not the same as the new Message feature Meetup added.

There were plans to add Group Search and Join, but it was taking a while to get the questions/profile page working and now Meetup has made that a required part of joining a group. I will continue to work on that and hopefully get that out soon.

Chat Reply 1 Chat Reply 2 Chat Reply 3

*** bug fixes ***

  • Fixed issue with splash screen and other image sizes, which was causing the app to be a much larger size than it should have been
  • Fixed progress and status indicators on Authentication and Feed screens
  • Albums refresh was not working
  • Fixed issue with Latitude and Longitude not providing correct location when mapping an event
  • Changed icon and splash screens in accordance with Meetup guidelines for logo useage

*** features ***

  • Added settings feature to clear user authentication to allow user to log in as a different user.
  • Added lower case “L” keyboard shortcut to “reload” Activity, Groups, Events and Albums
  • Added “Alt + f” keyboard shortcut to change focused tab to Feed on main screen
  • Added “Alt + g” keyboard shortcut to change focused tab to Groups on main screen
  • Added “Alt + e” keyboard shortcut to change focused tab to Events on main screen
  • Added Chat on Event and Reply to Chat on Event